Upgrade to Math::BigInt v1.65, Math::BigRat v0.10,
[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
7d341013 12# _f : flags, used by MBR to flag parts of a rationale as untouchable
184f15d5 13
14package Math::BigRat;
15
a4e2b1c6 16require 5.005_03;
184f15d5 17use strict;
18
19use Exporter;
20use Math::BigFloat;
21use vars qw($VERSION @ISA $PACKAGE @EXPORT_OK $upgrade $downgrade
990fb837 22 $accuracy $precision $round_mode $div_scale $_trap_nan $_trap_inf);
184f15d5 23
24@ISA = qw(Exporter Math::BigFloat);
25@EXPORT_OK = qw();
26
990fb837 27$VERSION = '0.10';
184f15d5 28
990fb837 29use overload; # inherit from Math::BigFloat
184f15d5 30
31##############################################################################
32# global constants, flags and accessory
33
184f15d5 34$accuracy = $precision = undef;
35$round_mode = 'even';
36$div_scale = 40;
37$upgrade = undef;
38$downgrade = undef;
39
990fb837 40# these are internally, and not to be used from the outside
41
42use constant MB_NEVER_ROUND => 0x0001;
43
44$_trap_nan = 0; # are NaNs ok? set w/ config()
45$_trap_inf = 0; # are infs ok? set w/ config()
46
184f15d5 47my $nan = 'NaN';
48my $class = 'Math::BigRat';
6de7f0cc 49my $MBI = 'Math::BigInt';
184f15d5 50
8f675a64 51sub isa
52 {
53 return 0 if $_[1] =~ /^Math::Big(Int|Float)/; # we aren't
54 UNIVERSAL::isa(@_);
55 }
56
184f15d5 57sub _new_from_float
58 {
7d341013 59 # turn a single float input into a rationale (like '0.1')
184f15d5 60 my ($self,$f) = @_;
61
62 return $self->bnan() if $f->is_nan();
63 return $self->binf('-inf') if $f->{sign} eq '-inf';
64 return $self->binf('+inf') if $f->{sign} eq '+inf';
65
184f15d5 66 $self->{_n} = $f->{_m}->copy(); # mantissa
6de7f0cc 67 $self->{_d} = $MBI->bone();
990fb837 68 $self->{sign} = $f->{sign} || '+'; $self->{_n}->{sign} = '+';
184f15d5 69 if ($f->{_e}->{sign} eq '-')
70 {
71 # something like Math::BigRat->new('0.1');
72 $self->{_d}->blsft($f->{_e}->copy()->babs(),10); # 1 / 1 => 1/10
73 }
74 else
75 {
76 # something like Math::BigRat->new('10');
77 # 1 / 1 => 10/1
78 $self->{_n}->blsft($f->{_e},10) unless $f->{_e}->is_zero();
79 }
184f15d5 80 $self;
81 }
82
83sub new
84 {
85 # create a Math::BigRat
86 my $class = shift;
87
88 my ($n,$d) = shift;
89
90 my $self = { }; bless $self,$class;
91
184f15d5 92 # input like (BigInt,BigInt) or (BigFloat,BigFloat) not handled yet
93
6de7f0cc 94 if ((!defined $d) && (ref $n) && (!$n->isa('Math::BigRat')))
184f15d5 95 {
184f15d5 96 if ($n->isa('Math::BigFloat'))
97 {
184f15d5 98 return $self->_new_from_float($n)->bnorm();
99 }
100 if ($n->isa('Math::BigInt'))
101 {
990fb837 102 # TODO: trap NaN, inf
8f675a64 103 $self->{_n} = $n->copy(); # "mantissa" = $n
6de7f0cc 104 $self->{_d} = $MBI->bone();
8f675a64 105 $self->{sign} = $self->{_n}->{sign}; $self->{_n}->{sign} = '+';
106 return $self->bnorm();
107 }
108 if ($n->isa('Math::BigInt::Lite'))
109 {
990fb837 110 # TODO: trap NaN, inf
111 $self->{sign} = '+'; $self->{sign} = '-' if $$n < 0;
112 $self->{_n} = $MBI->new(abs($$n),undef,undef); # "mantissa" = $n
6de7f0cc 113 $self->{_d} = $MBI->bone();
184f15d5 114 return $self->bnorm();
115 }
116 }
117 return $n->copy() if ref $n;
184f15d5 118
119 if (!defined $n)
120 {
7d341013 121 $self->{_n} = $MBI->bzero(); # undef => 0
6de7f0cc 122 $self->{_d} = $MBI->bone();
184f15d5 123 $self->{sign} = '+';
124 return $self->bnorm();
125 }
126 # string input with / delimiter
127 if ($n =~ /\s*\/\s*/)
128 {
990fb837 129 return $class->bnan() if $n =~ /\/.*\//; # 1/2/3 isn't valid
130 return $class->bnan() if $n =~ /\/\s*$/; # 1/ isn't valid
184f15d5 131 ($n,$d) = split (/\//,$n);
132 # try as BigFloats first
133 if (($n =~ /[\.eE]/) || ($d =~ /[\.eE]/))
134 {
135 # one of them looks like a float
7d341013 136 # Math::BigFloat($n,undef,undef) does not what it is supposed to do, so:
137 local $Math::BigFloat::accuracy = undef;
138 local $Math::BigFloat::precision = undef;
139 local $Math::BigInt::accuracy = undef;
140 local $Math::BigInt::precision = undef;
990fb837 141 my $nf = Math::BigFloat->new($n);
142 $self->{sign} = '+';
143 return $self->bnan() if $nf->is_nan();
144 $self->{_n} = $nf->{_m};
184f15d5 145 # now correct $self->{_n} due to $n
7d341013 146 my $f = Math::BigFloat->new($d,undef,undef);
990fb837 147 $self->{_d} = $f->{_m};
148 return $self->bnan() if $f->is_nan();
149 #print "n=$nf e$nf->{_e} d=$f e$f->{_e}\n";
150 # calculate the difference between nE and dE
151 my $diff_e = $nf->{_e}->copy()->bsub ( $f->{_e} );
152 if ($diff_e->is_negative())
153 {
154 # < 0: mul d with it
155 $self->{_d}->blsft($diff_e->babs(),10);
156 }
157 elsif (!$diff_e->is_zero())
184f15d5 158 {
990fb837 159 # > 0: mul n with it
160 $self->{_n}->blsft($diff_e,10);
184f15d5 161 }
184f15d5 162 }
163 else
164 {
7d341013 165 # both d and n are (big)ints
166 $self->{_n} = $MBI->new($n,undef,undef);
167 $self->{_d} = $MBI->new($d,undef,undef);
990fb837 168 $self->{sign} = '+';
169 return $self->bnan() if $self->{_n}->{sign} eq $nan ||
170 $self->{_d}->{sign} eq $nan;
184f15d5 171 # inf handling is missing here
990fb837 172 if ($self->{_n}->is_inf() || $self->{_d}->is_inf())
173 {
174 # inf/inf => NaN
175 return $self->bnan() if
176 ($self->{_n}->is_inf() && $self->{_d}->is_inf());
177 # +-inf/123 => +-inf
178 return $self->binf($self->{sign}) if $self->{_n}->is_inf();
179 # 123/inf => 0
180 return $self->bzero();
181 }
184f15d5 182
990fb837 183 $self->{sign} = $self->{_n}->{sign}; $self->{_n}->babs();
184f15d5 184 # if $d is negative, flip sign
185 $self->{sign} =~ tr/+-/-+/ if $self->{_d}->{sign} eq '-';
990fb837 186 $self->{_d}->babs(); # normalize
184f15d5 187 }
990fb837 188
184f15d5 189 return $self->bnorm();
190 }
191
192 # simple string input
193 if (($n =~ /[\.eE]/))
194 {
7d341013 195 # looks like a float, quacks like a float, so probably is a float
196 # Math::BigFloat($n,undef,undef) does not what it is supposed to do, so:
197 local $Math::BigFloat::accuracy = undef;
198 local $Math::BigFloat::precision = undef;
199 local $Math::BigInt::accuracy = undef;
200 local $Math::BigInt::precision = undef;
990fb837 201 $self->{sign} = 'NaN';
7d341013 202 $self->_new_from_float(Math::BigFloat->new($n,undef,undef));
184f15d5 203 }
204 else
205 {
7d341013 206 $self->{_n} = $MBI->new($n,undef,undef);
6de7f0cc 207 $self->{_d} = $MBI->bone();
990fb837 208 $self->{sign} = $self->{_n}->{sign}; $self->{_n}->babs();
a4e2b1c6 209 return $self->bnan() if $self->{sign} eq 'NaN';
210 return $self->binf($self->{sign}) if $self->{sign} =~ /^[+-]inf$/;
184f15d5 211 }
212 $self->bnorm();
213 }
214
990fb837 215##############################################################################
216
217sub config
218 {
219 # return (later set?) configuration data as hash ref
220 my $class = shift || 'Math::BigFloat';
221
222 my $cfg = $class->SUPER::config(@_);
223
224 # now we need only to override the ones that are different from our parent
225 $cfg->{class} = $class;
226 $cfg->{with} = $MBI;
227 $cfg;
228 }
229
230##############################################################################
8f675a64 231
184f15d5 232sub bstr
233 {
234 my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
235
236 if ($x->{sign} !~ /^[+-]$/) # inf, NaN etc
237 {
238 my $s = $x->{sign}; $s =~ s/^\+//; # +inf => inf
239 return $s;
240 }
241
184f15d5 242 my $s = ''; $s = $x->{sign} if $x->{sign} ne '+'; # +3 vs 3
243
244 return $s.$x->{_n}->bstr() if $x->{_d}->is_one();
245 return $s.$x->{_n}->bstr() . '/' . $x->{_d}->bstr();
246 }
247
248sub bsstr
249 {
250 my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
251
252 if ($x->{sign} !~ /^[+-]$/) # inf, NaN etc
253 {
254 my $s = $x->{sign}; $s =~ s/^\+//; # +inf => inf
255 return $s;
256 }
257
258 my $s = ''; $s = $x->{sign} if $x->{sign} ne '+'; # +3 vs 3
7d341013 259 return $s . $x->{_n}->bstr() . '/' . $x->{_d}->bstr();
184f15d5 260 }
261
262sub bnorm
263 {
264 # reduce the number to the shortest form and remember this (so that we
265 # don't reduce again)
266 my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
267
990fb837 268 # both parts must be BigInt's (or whatever we are using today)
269 if (ref($x->{_n}) ne $MBI)
270 {
271 require Carp; Carp::croak ("n is not $MBI but (".ref($x->{_n}).')');
272 }
273 if (ref($x->{_d}) ne $MBI)
274 {
275 require Carp; Carp::croak ("d is not $MBI but (".ref($x->{_d}).')');
276 }
6de7f0cc 277
184f15d5 278 # this is to prevent automatically rounding when MBI's globals are set
279 $x->{_d}->{_f} = MB_NEVER_ROUND;
280 $x->{_n}->{_f} = MB_NEVER_ROUND;
281 # 'forget' that parts were rounded via MBI::bround() in MBF's bfround()
282 $x->{_d}->{_a} = undef; $x->{_n}->{_a} = undef;
283 $x->{_d}->{_p} = undef; $x->{_n}->{_p} = undef;
284
6de7f0cc 285 # no normalize for NaN, inf etc.
286 return $x if $x->{sign} !~ /^[+-]$/;
287
184f15d5 288 # normalize zeros to 0/1
289 if (($x->{sign} =~ /^[+-]$/) &&
290 ($x->{_n}->is_zero()))
291 {
a4e2b1c6 292 $x->{sign} = '+'; # never -0
6de7f0cc 293 $x->{_d} = $MBI->bone() unless $x->{_d}->is_one();
184f15d5 294 return $x;
295 }
296
a4e2b1c6 297 return $x if $x->{_d}->is_one(); # no need to reduce
6de7f0cc 298
184f15d5 299 # reduce other numbers
8f675a64 300 # disable upgrade in BigInt, otherwise deep recursion
301 local $Math::BigInt::upgrade = undef;
7d341013 302 local $Math::BigInt::accuracy = undef;
303 local $Math::BigInt::precision = undef;
184f15d5 304 my $gcd = $x->{_n}->bgcd($x->{_d});
305
306 if (!$gcd->is_one())
307 {
308 $x->{_n}->bdiv($gcd);
309 $x->{_d}->bdiv($gcd);
310 }
184f15d5 311 $x;
312 }
313
314##############################################################################
315# special values
316
317sub _bnan
318 {
990fb837 319 # used by parent class bnan() to initialize number to NaN
184f15d5 320 my $self = shift;
990fb837 321
322 if ($_trap_nan)
323 {
324 require Carp;
325 my $class = ref($self);
326 Carp::croak ("Tried to set $self to NaN in $class\::_bnan()");
327 }
a4e2b1c6 328 $self->{_n} = $MBI->bzero();
329 $self->{_d} = $MBI->bzero();
184f15d5 330 }
331
332sub _binf
333 {
7d341013 334 # used by parent class bone() to initialize number to +inf/-inf
184f15d5 335 my $self = shift;
990fb837 336
337 if ($_trap_inf)
338 {
339 require Carp;
340 my $class = ref($self);
341 Carp::croak ("Tried to set $self to inf in $class\::_binf()");
342 }
a4e2b1c6 343 $self->{_n} = $MBI->bzero();
344 $self->{_d} = $MBI->bzero();
184f15d5 345 }
346
347sub _bone
348 {
7d341013 349 # used by parent class bone() to initialize number to +1/-1
184f15d5 350 my $self = shift;
a4e2b1c6 351 $self->{_n} = $MBI->bone();
352 $self->{_d} = $MBI->bone();
184f15d5 353 }
354
355sub _bzero
356 {
990fb837 357 # used by parent class bzero() to initialize number to 0
184f15d5 358 my $self = shift;
a4e2b1c6 359 $self->{_n} = $MBI->bzero();
360 $self->{_d} = $MBI->bone();
184f15d5 361 }
362
363##############################################################################
364# mul/add/div etc
365
366sub badd
367 {
7d341013 368 # add two rationales
369
370 # set up parameters
371 my ($self,$x,$y,@r) = (ref($_[0]),@_);
372 # objectify is costly, so avoid it
373 if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
374 {
375 ($self,$x,$y,@r) = objectify(2,@_);
376 }
184f15d5 377
6de7f0cc 378 $x = $self->new($x) unless $x->isa($self);
379 $y = $self->new($y) unless $y->isa($self);
184f15d5 380
8f675a64 381 return $x->bnan() if ($x->{sign} eq 'NaN' || $y->{sign} eq 'NaN');
7d341013 382 # TODO: inf handling
184f15d5 383
384 # 1 1 gcd(3,4) = 1 1*3 + 1*4 7
385 # - + - = --------- = --
386 # 4 3 4*3 12
387
7d341013 388 # we do not compute the gcd() here, but simple do:
389 # 5 7 5*3 + 7*4 41
390 # - + - = --------- = --
391 # 4 3 4*3 12
392
393 # the gcd() calculation and reducing is then done in bnorm()
184f15d5 394
7d341013 395 local $Math::BigInt::accuracy = undef;
396 local $Math::BigInt::precision = undef;
397
398 $x->{_n}->bmul($y->{_d}); $x->{_n}->{sign} = $x->{sign};
399 my $m = $y->{_n}->copy()->bmul($x->{_d});
184f15d5 400 $m->{sign} = $y->{sign}; # 2/1 - 2/1
401 $x->{_n}->badd($m);
402
403 $x->{_d}->bmul($y->{_d});
404
405 # calculate new sign
406 $x->{sign} = $x->{_n}->{sign}; $x->{_n}->{sign} = '+';
407
7d341013 408 $x->bnorm()->round(@r);
184f15d5 409 }
410
411sub bsub
412 {
7d341013 413 # subtract two rationales
414
415 # set up parameters
416 my ($self,$x,$y,@r) = (ref($_[0]),@_);
417 # objectify is costly, so avoid it
418 if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
419 {
420 ($self,$x,$y,@r) = objectify(2,@_);
421 }
184f15d5 422
990fb837 423 # TODO: $self instead or $class??
8f675a64 424 $x = $class->new($x) unless $x->isa($class);
425 $y = $class->new($y) unless $y->isa($class);
426
184f15d5 427 return $x->bnan() if ($x->{sign} eq 'NaN' || $y->{sign} eq 'NaN');
428 # TODO: inf handling
429
7d341013 430 # 1 1 gcd(3,4) = 1 1*3 - 1*4 7
431 # - - - = --------- = --
184f15d5 432 # 4 3 4*3 12
7d341013 433
434 # we do not compute the gcd() here, but simple do:
435 # 5 7 5*3 - 7*4 13
436 # - - - = --------- = - --
437 # 4 3 4*3 12
184f15d5 438
7d341013 439 local $Math::BigInt::accuracy = undef;
440 local $Math::BigInt::precision = undef;
184f15d5 441
7d341013 442 $x->{_n}->bmul($y->{_d}); $x->{_n}->{sign} = $x->{sign};
443 my $m = $y->{_n}->copy()->bmul($x->{_d});
184f15d5 444 $m->{sign} = $y->{sign}; # 2/1 - 2/1
445 $x->{_n}->bsub($m);
446
447 $x->{_d}->bmul($y->{_d});
448
449 # calculate new sign
450 $x->{sign} = $x->{_n}->{sign}; $x->{_n}->{sign} = '+';
451
7d341013 452 $x->bnorm()->round(@r);
184f15d5 453 }
454
455sub bmul
456 {
7d341013 457 # multiply two rationales
458
459 # set up parameters
460 my ($self,$x,$y,@r) = (ref($_[0]),@_);
461 # objectify is costly, so avoid it
462 if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
463 {
464 ($self,$x,$y,@r) = objectify(2,@_);
465 }
184f15d5 466
990fb837 467 # TODO: $self instead or $class??
8f675a64 468 $x = $class->new($x) unless $x->isa($class);
469 $y = $class->new($y) unless $y->isa($class);
470
184f15d5 471 return $x->bnan() if ($x->{sign} eq 'NaN' || $y->{sign} eq 'NaN');
472
473 # inf handling
474 if (($x->{sign} =~ /^[+-]inf$/) || ($y->{sign} =~ /^[+-]inf$/))
475 {
476 return $x->bnan() if $x->is_zero() || $y->is_zero();
477 # result will always be +-inf:
478 # +inf * +/+inf => +inf, -inf * -/-inf => +inf
479 # +inf * -/-inf => -inf, -inf * +/+inf => -inf
480 return $x->binf() if ($x->{sign} =~ /^\+/ && $y->{sign} =~ /^\+/);
481 return $x->binf() if ($x->{sign} =~ /^-/ && $y->{sign} =~ /^-/);
482 return $x->binf('-');
483 }
484
485 # x== 0 # also: or y == 1 or y == -1
486 return wantarray ? ($x,$self->bzero()) : $x if $x->is_zero();
487
184f15d5 488 # According to Knuth, this can be optimized by doingtwice gcd (for d and n)
489 # and reducing in one step)
490
491 # 1 1 2 1
492 # - * - = - = -
493 # 4 3 12 6
7d341013 494
495 local $Math::BigInt::accuracy = undef;
496 local $Math::BigInt::precision = undef;
184f15d5 497 $x->{_n}->bmul($y->{_n});
498 $x->{_d}->bmul($y->{_d});
499
500 # compute new sign
501 $x->{sign} = $x->{sign} eq $y->{sign} ? '+' : '-';
502
7d341013 503 $x->bnorm()->round(@r);
184f15d5 504 }
505
506sub bdiv
507 {
508 # (dividend: BRAT or num_str, divisor: BRAT or num_str) return
509 # (BRAT,BRAT) (quo,rem) or BRAT (only rem)
7d341013 510
511 # set up parameters
512 my ($self,$x,$y,@r) = (ref($_[0]),@_);
513 # objectify is costly, so avoid it
514 if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
515 {
516 ($self,$x,$y,@r) = objectify(2,@_);
517 }
184f15d5 518
990fb837 519 # TODO: $self instead or $class??
8f675a64 520 $x = $class->new($x) unless $x->isa($class);
521 $y = $class->new($y) unless $y->isa($class);
522
184f15d5 523 return $self->_div_inf($x,$y)
524 if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/) || $y->is_zero());
525
526 # x== 0 # also: or y == 1 or y == -1
527 return wantarray ? ($x,$self->bzero()) : $x if $x->is_zero();
528
529 # TODO: list context, upgrade
530
184f15d5 531 # 1 1 1 3
532 # - / - == - * -
533 # 4 3 4 1
7d341013 534
535# local $Math::BigInt::accuracy = undef;
536# local $Math::BigInt::precision = undef;
184f15d5 537 $x->{_n}->bmul($y->{_d});
538 $x->{_d}->bmul($y->{_n});
539
540 # compute new sign
541 $x->{sign} = $x->{sign} eq $y->{sign} ? '+' : '-';
542
7d341013 543 $x->bnorm()->round(@r);
6de7f0cc 544 $x;
184f15d5 545 }
546
990fb837 547sub bmod
548 {
549 # compute "remainder" (in Perl way) of $x / $y
550
551 # set up parameters
552 my ($self,$x,$y,@r) = (ref($_[0]),@_);
553 # objectify is costly, so avoid it
554 if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
555 {
556 ($self,$x,$y,@r) = objectify(2,@_);
557 }
558
559 # TODO: $self instead or $class??
560 $x = $class->new($x) unless $x->isa($class);
561 $y = $class->new($y) unless $y->isa($class);
562
563 return $self->_div_inf($x,$y)
564 if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/) || $y->is_zero());
565
566 return $self->_div_inf($x,$y)
567 if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/) || $y->is_zero());
568
569 return $x if $x->is_zero(); # 0 / 7 = 0, mod 0
570
571 # compute $x - $y * floor($x/$y), keeping the sign of $x
572
573 local $Math::BigInt::upgrade = undef;
574 local $Math::BigInt::accuracy = undef;
575 local $Math::BigInt::precision = undef;
576
577 my $u = $x->copy()->babs();
578 # do a "normal" division ($x/$y)
579 $u->{_d}->bmul($y->{_n});
580 $u->{_n}->bmul($y->{_d});
581
582 # compute floor
583 if (!$u->{_d}->is_one())
584 {
585 $u->{_n}->bdiv($u->{_d}); # 22/7 => 3/1 w/ truncate
586 # no need to set $u->{_d} to 1, since later we set it to $y->{_d}
587 #$x->{_n}->binc() if $x->{sign} eq '-'; # -22/7 => -4/1
588 }
589
590 # compute $y * $u
591 $u->{_d} = $y->{_d}; # 1 * $y->{_d}, see floor above
592 $u->{_n}->bmul($y->{_n});
593
594 my $xsign = $x->{sign}; $x->{sign} = '+'; # remember sign and make abs
595 # compute $x - $u
596 $x->bsub($u);
597 $x->{sign} = $xsign; # put sign back
598
599 $x->bnorm()->round(@r);
600 $x;
601 }
602
184f15d5 603##############################################################################
a4e2b1c6 604# bdec/binc
605
606sub bdec
607 {
608 # decrement value (subtract 1)
609 my ($self,$x,@r) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_);
610
611 return $x if $x->{sign} !~ /^[+-]$/; # NaN, inf, -inf
612
613 if ($x->{sign} eq '-')
614 {
615 $x->{_n}->badd($x->{_d}); # -5/2 => -7/2
616 }
617 else
618 {
619 if ($x->{_n}->bacmp($x->{_d}) < 0)
620 {
621 # 1/3 -- => -2/3
622 $x->{_n} = $x->{_d} - $x->{_n};
623 $x->{sign} = '-';
624 }
625 else
626 {
627 $x->{_n}->bsub($x->{_d}); # 5/2 => 3/2
628 }
629 }
630 $x->bnorm()->round(@r);
a4e2b1c6 631 }
632
633sub binc
634 {
635 # increment value (add 1)
636 my ($self,$x,@r) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_);
637
638 return $x if $x->{sign} !~ /^[+-]$/; # NaN, inf, -inf
639
640 if ($x->{sign} eq '-')
641 {
642 if ($x->{_n}->bacmp($x->{_d}) < 0)
643 {
644 # -1/3 ++ => 2/3 (overflow at 0)
645 $x->{_n} = $x->{_d} - $x->{_n};
646 $x->{sign} = '+';
647 }
648 else
649 {
650 $x->{_n}->bsub($x->{_d}); # -5/2 => -3/2
651 }
652 }
653 else
654 {
655 $x->{_n}->badd($x->{_d}); # 5/2 => 7/2
656 }
657 $x->bnorm()->round(@r);
a4e2b1c6 658 }
659
660##############################################################################
184f15d5 661# is_foo methods (the rest is inherited)
662
663sub is_int
664 {
665 # return true if arg (BRAT or num_str) is an integer
666 my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
667
668 return 1 if ($x->{sign} =~ /^[+-]$/) && # NaN and +-inf aren't
7d341013 669 $x->{_d}->is_one(); # x/y && y != 1 => no integer
184f15d5 670 0;
671 }
672
673sub is_zero
674 {
675 # return true if arg (BRAT or num_str) is zero
676 my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
677
678 return 1 if $x->{sign} eq '+' && $x->{_n}->is_zero();
679 0;
680 }
681
682sub is_one
683 {
684 # return true if arg (BRAT or num_str) is +1 or -1 if signis given
685 my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
686
687 my $sign = shift || ''; $sign = '+' if $sign ne '-';
688 return 1
689 if ($x->{sign} eq $sign && $x->{_n}->is_one() && $x->{_d}->is_one());
690 0;
691 }
692
693sub is_odd
694 {
695 # return true if arg (BFLOAT or num_str) is odd or false if even
696 my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
697
698 return 1 if ($x->{sign} =~ /^[+-]$/) && # NaN & +-inf aren't
699 ($x->{_d}->is_one() && $x->{_n}->is_odd()); # x/2 is not, but 3/1
700 0;
701 }
702
703sub is_even
704 {
705 # return true if arg (BINT or num_str) is even or false if odd
706 my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
707
708 return 0 if $x->{sign} !~ /^[+-]$/; # NaN & +-inf aren't
709 return 1 if ($x->{_d}->is_one() # x/3 is never
710 && $x->{_n}->is_even()); # but 4/1 is
711 0;
712 }
713
714BEGIN
715 {
716 *objectify = \&Math::BigInt::objectify;
717 }
718
719##############################################################################
720# parts() and friends
721
722sub numerator
723 {
724 my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
a4e2b1c6 725
726 return $MBI->new($x->{sign}) if ($x->{sign} !~ /^[+-]$/);
727
184f15d5 728 my $n = $x->{_n}->copy(); $n->{sign} = $x->{sign};
729 $n;
730 }
731
732sub denominator
733 {
734 my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
735
a4e2b1c6 736 return $MBI->new($x->{sign}) if ($x->{sign} !~ /^[+-]$/);
184f15d5 737 $x->{_d}->copy();
738 }
739
740sub parts
741 {
742 my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
743
a4e2b1c6 744 return ($self->bnan(),$self->bnan()) if $x->{sign} eq 'NaN';
745 return ($self->binf(),$self->binf()) if $x->{sign} eq '+inf';
746 return ($self->binf('-'),$self->binf()) if $x->{sign} eq '-inf';
747
184f15d5 748 my $n = $x->{_n}->copy();
749 $n->{sign} = $x->{sign};
a4e2b1c6 750 return ($n,$x->{_d}->copy());
184f15d5 751 }
752
753sub length
754 {
755 return 0;
756 }
757
758sub digit
759 {
760 return 0;
761 }
762
763##############################################################################
764# special calc routines
765
766sub bceil
767 {
768 my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
769
770 return $x unless $x->{sign} =~ /^[+-]$/;
771 return $x if $x->{_d}->is_one(); # 22/1 => 22, 0/1 => 0
772
990fb837 773 local $Math::BigInt::upgrade = undef;
774 local $Math::BigInt::accuracy = undef;
775 local $Math::BigInt::precision = undef;
a4e2b1c6 776 $x->{_n}->bdiv($x->{_d}); # 22/7 => 3/1 w/ truncate
184f15d5 777 $x->{_d}->bone();
778 $x->{_n}->binc() if $x->{sign} eq '+'; # +22/7 => 4/1
a4e2b1c6 779 $x->{sign} = '+' if $x->{_n}->is_zero(); # -0 => 0
184f15d5 780 $x;
781 }
782
783sub bfloor
784 {
785 my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
786
787 return $x unless $x->{sign} =~ /^[+-]$/;
788 return $x if $x->{_d}->is_one(); # 22/1 => 22, 0/1 => 0
789
990fb837 790 local $Math::BigInt::upgrade = undef;
791 local $Math::BigInt::accuracy = undef;
792 local $Math::BigInt::precision = undef;
a4e2b1c6 793 $x->{_n}->bdiv($x->{_d}); # 22/7 => 3/1 w/ truncate
184f15d5 794 $x->{_d}->bone();
795 $x->{_n}->binc() if $x->{sign} eq '-'; # -22/7 => -4/1
796 $x;
797 }
798
799sub bfac
800 {
a4e2b1c6 801 my ($self,$x,@r) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_);
802
803 if (($x->{sign} eq '+') && ($x->{_d}->is_one()))
804 {
805 $x->{_n}->bfac();
806 return $x->round(@r);
807 }
808 $x->bnan();
184f15d5 809 }
810
811sub bpow
812 {
7d341013 813 # power ($x ** $y)
814
815 # set up parameters
816 my ($self,$x,$y,@r) = (ref($_[0]),@_);
817 # objectify is costly, so avoid it
818 if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
819 {
820 ($self,$x,$y,@r) = objectify(2,@_);
821 }
184f15d5 822
823 return $x if $x->{sign} =~ /^[+-]inf$/; # -inf/+inf ** x
824 return $x->bnan() if $x->{sign} eq $nan || $y->{sign} eq $nan;
825 return $x->bone(@r) if $y->is_zero();
826 return $x->round(@r) if $x->is_one() || $y->is_one();
827 if ($x->{sign} eq '-' && $x->{_n}->is_one() && $x->{_d}->is_one())
828 {
829 # if $x == -1 and odd/even y => +1/-1
830 return $y->is_odd() ? $x->round(@r) : $x->babs()->round(@r);
831 # my Casio FX-5500L has a bug here: -1 ** 2 is -1, but -1 * -1 is 1;
832 }
833 # 1 ** -y => 1 / (1 ** |y|)
834 # so do test for negative $y after above's clause
835 # return $x->bnan() if $y->{sign} eq '-';
836 return $x->round(@r) if $x->is_zero(); # 0**y => 0 (if not y <= 0)
837
a4e2b1c6 838 # shortcut y/1 (and/or x/1)
839 if ($y->{_d}->is_one())
840 {
841 # shortcut for x/1 and y/1
842 if ($x->{_d}->is_one())
843 {
844 $x->{_n}->bpow($y->{_n}); # x/1 ** y/1 => (x ** y)/1
845 if ($y->{sign} eq '-')
846 {
847 # 0.2 ** -3 => 1/(0.2 ** 3)
848 ($x->{_n},$x->{_d}) = ($x->{_d},$x->{_n}); # swap
849 }
850 # correct sign; + ** + => +
851 if ($x->{sign} eq '-')
852 {
853 # - * - => +, - * - * - => -
854 $x->{sign} = '+' if $y->{_n}->is_even();
855 }
856 return $x->round(@r);
857 }
858 # x/z ** y/1
859 $x->{_n}->bpow($y->{_n}); # 5/2 ** y/1 => 5 ** y / 2 ** y
860 $x->{_d}->bpow($y->{_n});
861 if ($y->{sign} eq '-')
862 {
863 # 0.2 ** -3 => 1/(0.2 ** 3)
864 ($x->{_n},$x->{_d}) = ($x->{_d},$x->{_n}); # swap
865 }
866 # correct sign; + ** + => +
867 if ($x->{sign} eq '-')
868 {
869 # - * - => +, - * - * - => -
870 $x->{sign} = '+' if $y->{_n}->is_even();
871 }
872 return $x->round(@r);
873 }
874
875 # regular calculation (this is wrong for d/e ** f/g)
184f15d5 876 my $pow2 = $self->__one();
a4e2b1c6 877 my $y1 = $MBI->new($y->{_n}/$y->{_d})->babs();
878 my $two = $MBI->new(2);
184f15d5 879 while (!$y1->is_one())
880 {
184f15d5 881 $pow2->bmul($x) if $y1->is_odd();
882 $y1->bdiv($two);
883 $x->bmul($x);
884 }
885 $x->bmul($pow2) unless $pow2->is_one();
886 # n ** -x => 1/n ** x
887 ($x->{_d},$x->{_n}) = ($x->{_n},$x->{_d}) if $y->{sign} eq '-';
7d341013 888 $x->bnorm()->round(@r);
184f15d5 889 }
890
891sub blog
892 {
893 return Math::BigRat->bnan();
894 }
895
896sub bsqrt
897 {
990fb837 898 my ($self,$x,@r) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_);
899
900 return $x->bnan() if $x->{sign} !~ /^[+]/; # NaN, -inf or < 0
901 return $x if $x->{sign} eq '+inf'; # sqrt(inf) == inf
902 return $x->round(@r) if $x->is_zero() || $x->is_one();
903
904 local $Math::BigFloat::upgrade = undef;
905 local $Math::BigFloat::downgrade = undef;
906 local $Math::BigFloat::precision = undef;
907 local $Math::BigFloat::accuracy = undef;
908 local $Math::BigInt::upgrade = undef;
909 local $Math::BigInt::precision = undef;
910 local $Math::BigInt::accuracy = undef;
911 $x->{_d} = Math::BigFloat->new($x->{_d})->bsqrt(@r);
912 $x->{_n} = Math::BigFloat->new($x->{_n})->bsqrt(@r);
184f15d5 913
990fb837 914 # if sqrt(D) was not integer
915 if ($x->{_d}->{_e}->{sign} ne '+')
916 {
917 $x->{_n}->blsft($x->{_d}->{_e}->babs(),10); # 7.1/4.51 => 7.1/45.1
918 $x->{_d} = $x->{_d}->{_m}; # 7.1/45.1 => 71/45.1
919 }
920 # if sqrt(N) was not integer
921 if ($x->{_n}->{_e}->{sign} ne '+')
922 {
923 $x->{_d}->blsft($x->{_n}->{_e}->babs(),10); # 71/45.1 => 710/45.1
924 $x->{_n} = $x->{_n}->{_n}; # 710/45.1 => 710/451
925 }
926
927 # convert parts to $MBI again
928 $x->{_n} = $x->{_n}->as_number();
929 $x->{_d} = $x->{_d}->as_number();
930 $x->bnorm()->round(@r);
184f15d5 931 }
932
933sub blsft
934 {
935 my ($self,$x,$y,$b,$a,$p,$r) = objectify(3,@_);
936
937 $x->bmul( $b->copy()->bpow($y), $a,$p,$r);
938 $x;
939 }
940
941sub brsft
942 {
943 my ($self,$x,$y,$b,$a,$p,$r) = objectify(2,@_);
944
945 $x->bdiv( $b->copy()->bpow($y), $a,$p,$r);
946 $x;
947 }
948
949##############################################################################
950# round
951
952sub round
953 {
954 $_[0];
955 }
956
957sub bround
958 {
959 $_[0];
960 }
961
962sub bfround
963 {
964 $_[0];
965 }
966
967##############################################################################
968# comparing
969
970sub bcmp
971 {
972 my ($self,$x,$y) = objectify(2,@_);
973
974 if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/))
975 {
976 # handle +-inf and NaN
977 return undef if (($x->{sign} eq $nan) || ($y->{sign} eq $nan));
978 return 0 if $x->{sign} eq $y->{sign} && $x->{sign} =~ /^[+-]inf$/;
979 return +1 if $x->{sign} eq '+inf';
980 return -1 if $x->{sign} eq '-inf';
981 return -1 if $y->{sign} eq '+inf';
982 return +1;
983 }
984 # check sign for speed first
985 return 1 if $x->{sign} eq '+' && $y->{sign} eq '-'; # does also 0 <=> -y
986 return -1 if $x->{sign} eq '-' && $y->{sign} eq '+'; # does also -x <=> 0
987
988 # shortcut
989 my $xz = $x->{_n}->is_zero();
990 my $yz = $y->{_n}->is_zero();
991 return 0 if $xz && $yz; # 0 <=> 0
992 return -1 if $xz && $y->{sign} eq '+'; # 0 <=> +y
993 return 1 if $yz && $x->{sign} eq '+'; # +x <=> 0
994
995 my $t = $x->{_n} * $y->{_d}; $t->{sign} = $x->{sign};
996 my $u = $y->{_n} * $x->{_d}; $u->{sign} = $y->{sign};
997 $t->bcmp($u);
998 }
999
1000sub bacmp
1001 {
1002 my ($self,$x,$y) = objectify(2,@_);
1003
1004 if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/))
1005 {
1006 # handle +-inf and NaN
1007 return undef if (($x->{sign} eq $nan) || ($y->{sign} eq $nan));
1008 return 0 if $x->{sign} =~ /^[+-]inf$/ && $y->{sign} =~ /^[+-]inf$/;
1009 return +1; # inf is always bigger
1010 }
1011
1012 my $t = $x->{_n} * $y->{_d};
1013 my $u = $y->{_n} * $x->{_d};
1014 $t->bacmp($u);
1015 }
1016
1017##############################################################################
1018# output conversation
1019
7d341013 1020sub numify
1021 {
1022 # convert 17/8 => float (aka 2.125)
1023 my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
1024
1025 return $x->bstr() if $x->{sign} !~ /^[+-]$/; # inf, NaN, etc
1026
1027 my $t = Math::BigFloat->new($x->{_n});
1028 $t->bneg() if $x->is_negative();
1029 $t->bdiv($x->{_d});
1030 $t->numify();
1031 }
1032
184f15d5 1033sub as_number
1034 {
1035 my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
1036
990fb837 1037 return $x if $x->{sign} !~ /^[+-]$/; # NaN, inf etc
1038
1039 # need to disable these, otherwise bdiv() gives BigRat again
1040 local $Math::BigInt::upgrade = undef;
1041 local $Math::BigInt::accuracy = undef;
1042 local $Math::BigInt::precision = undef;
184f15d5 1043 my $t = $x->{_n}->copy()->bdiv($x->{_d}); # 22/7 => 3
1044 $t->{sign} = $x->{sign};
1045 $t;
1046 }
1047
6de7f0cc 1048sub import
1049 {
1050 my $self = shift;
1051 my $l = scalar @_;
1052 my $lib = ''; my @a;
1053 for ( my $i = 0; $i < $l ; $i++)
1054 {
1055# print "at $_[$i] (",$_[$i+1]||'undef',")\n";
1056 if ( $_[$i] eq ':constant' )
1057 {
1058 # this rest causes overlord er load to step in
1059 # print "overload @_\n";
1060 overload::constant float => sub { $self->new(shift); };
1061 }
1062# elsif ($_[$i] eq 'upgrade')
1063# {
1064# # this causes upgrading
1065# $upgrade = $_[$i+1]; # or undef to disable
1066# $i++;
1067# }
1068 elsif ($_[$i] eq 'downgrade')
1069 {
1070 # this causes downgrading
1071 $downgrade = $_[$i+1]; # or undef to disable
1072 $i++;
1073 }
1074 elsif ($_[$i] eq 'lib')
1075 {
1076 $lib = $_[$i+1] || ''; # default Calc
1077 $i++;
1078 }
1079 elsif ($_[$i] eq 'with')
1080 {
1081 $MBI = $_[$i+1] || 'Math::BigInt'; # default Math::BigInt
1082 $i++;
1083 }
1084 else
1085 {
1086 push @a, $_[$i];
1087 }
1088 }
1089 # let use Math::BigInt lib => 'GMP'; use Math::BigFloat; still work
1090 my $mbilib = eval { Math::BigInt->config()->{lib} };
1091 if ((defined $mbilib) && ($MBI eq 'Math::BigInt'))
1092 {
1093 # MBI already loaded
1094 $MBI->import('lib',"$lib,$mbilib", 'objectify');
1095 }
1096 else
1097 {
a4e2b1c6 1098 # MBI not loaded, or not with "Math::BigInt"
6de7f0cc 1099 $lib .= ",$mbilib" if defined $mbilib;
1100
6de7f0cc 1101 if ($] < 5.006)
1102 {
1103 # Perl < 5.6.0 dies with "out of memory!" when eval() and ':constant' is
1104 # used in the same script, or eval inside import().
1105 my @parts = split /::/, $MBI; # Math::BigInt => Math BigInt
1106 my $file = pop @parts; $file .= '.pm'; # BigInt => BigInt.pm
1107 $file = File::Spec->catfile (@parts, $file);
1108 eval { require $file; $MBI->import( lib => '$lib', 'objectify' ); }
1109 }
1110 else
1111 {
1112 my $rc = "use $MBI lib => '$lib', 'objectify';";
1113 eval $rc;
1114 }
1115 }
1116 die ("Couldn't load $MBI: $! $@") if $@;
1117
1118 # any non :constant stuff is handled by our parent, Exporter
1119 # even if @_ is empty, to give it a chance
1120 $self->SUPER::import(@a); # for subclasses
1121 $self->export_to_level(1,$self,@a); # need this, too
1122 }
184f15d5 1123
11241;
1125
1126__END__
1127
1128=head1 NAME
1129
7d341013 1130Math::BigRat - arbitrarily big rationales
184f15d5 1131
1132=head1 SYNOPSIS
1133
7d341013 1134 use Math::BigRat;
184f15d5 1135
7d341013 1136 $x = Math::BigRat->new('3/7'); $x += '5/9';
184f15d5 1137
7d341013 1138 print $x->bstr(),"\n";
1139 print $x ** 2,"\n";
184f15d5 1140
1141=head1 DESCRIPTION
1142
7d341013 1143Math::BigRat complements Math::BigInt and Math::BigFloat by providing support
1144for arbitrarily big rationales.
184f15d5 1145
1146=head2 MATH LIBRARY
1147
1148Math with the numbers is done (by default) by a module called
1149Math::BigInt::Calc. This is equivalent to saying:
1150
1151 use Math::BigRat lib => 'Calc';
1152
1153You can change this by using:
1154
1155 use Math::BigRat lib => 'BitVect';
1156
1157The following would first try to find Math::BigInt::Foo, then
1158Math::BigInt::Bar, and when this also fails, revert to Math::BigInt::Calc:
1159
1160 use Math::BigRat lib => 'Foo,Math::BigInt::Bar';
1161
1162Calc.pm uses as internal format an array of elements of some decimal base
7d341013 1163(usually 1e7, but this might be different for some systems) with the least
184f15d5 1164significant digit first, while BitVect.pm uses a bit vector of base 2, most
1165significant bit first. Other modules might use even different means of
1166representing the numbers. See the respective module documentation for further
1167details.
1168
7d341013 1169Currently the following replacement libraries exist, search for them at CPAN:
1170
1171 Math::BigInt::BitVect
1172 Math::BigInt::GMP
1173 Math::BigInt::Pari
1174 Math::BigInt::FastCalc
1175
184f15d5 1176=head1 METHODS
1177
7d341013 1178Any methods not listed here are dervied from Math::BigFloat (or
6de7f0cc 1179Math::BigInt), so make sure you check these two modules for further
1180information.
1181
1182=head2 new()
184f15d5 1183
1184 $x = Math::BigRat->new('1/3');
1185
1186Create a new Math::BigRat object. Input can come in various forms:
1187
7d341013 1188 $x = Math::BigRat->new(123); # scalars
1189 $x = Math::BigRat->new('123.3'); # float
184f15d5 1190 $x = Math::BigRat->new('1/3'); # simple string
1191 $x = Math::BigRat->new('1 / 3'); # spaced
1192 $x = Math::BigRat->new('1 / 0.1'); # w/ floats
1193 $x = Math::BigRat->new(Math::BigInt->new(3)); # BigInt
1194 $x = Math::BigRat->new(Math::BigFloat->new('3.1')); # BigFloat
6de7f0cc 1195 $x = Math::BigRat->new(Math::BigInt::Lite->new('2')); # BigLite
184f15d5 1196
6de7f0cc 1197=head2 numerator()
184f15d5 1198
1199 $n = $x->numerator();
1200
1201Returns a copy of the numerator (the part above the line) as signed BigInt.
1202
6de7f0cc 1203=head2 denominator()
184f15d5 1204
1205 $d = $x->denominator();
1206
1207Returns a copy of the denominator (the part under the line) as positive BigInt.
1208
6de7f0cc 1209=head2 parts()
184f15d5 1210
1211 ($n,$d) = $x->parts();
1212
1213Return a list consisting of (signed) numerator and (unsigned) denominator as
1214BigInts.
1215
6de7f0cc 1216=head2 as_number()
1217
7d341013 1218 $x = Math::BigRat->new('13/7');
1219 print $x->as_number(),"\n"; # '1'
1220
990fb837 1221Returns a copy of the object as BigInt trunced it to integer.
6de7f0cc 1222
a4e2b1c6 1223=head2 bfac()
6de7f0cc 1224
a4e2b1c6 1225 $x->bfac();
6de7f0cc 1226
a4e2b1c6 1227Calculates the factorial of $x. For instance:
6de7f0cc 1228
a4e2b1c6 1229 print Math::BigRat->new('3/1')->bfac(),"\n"; # 1*2*3
1230 print Math::BigRat->new('5/1')->bfac(),"\n"; # 1*2*3*4*5
184f15d5 1231
7d341013 1232Works currently only for integers.
6de7f0cc 1233
a4e2b1c6 1234=head2 blog()
6de7f0cc 1235
a4e2b1c6 1236Is not yet implemented.
6de7f0cc 1237
a4e2b1c6 1238=head2 bround()/round()/bfround()
6de7f0cc 1239
a4e2b1c6 1240Are not yet implemented.
6de7f0cc 1241
990fb837 1242=head2 bmod()
1243
1244 use Math::BigRat;
1245 my $x = Math::BigRat->new('7/4');
1246 my $y = Math::BigRat->new('4/3');
1247 print $x->bmod($y);
1248
1249Set $x to the remainder of the division of $x by $y.
1250
7d341013 1251=head2 is_one()
1252
1253 print "$x is 1\n" if $x->is_one();
1254
1255Return true if $x is exactly one, otherwise false.
1256
1257=head2 is_zero()
1258
1259 print "$x is 0\n" if $x->is_zero();
1260
1261Return true if $x is exactly zero, otherwise false.
1262
1263=head2 is_positive()
1264
1265 print "$x is >= 0\n" if $x->is_positive();
1266
1267Return true if $x is positive (greater than or equal to zero), otherwise
1268false. Please note that '+inf' is also positive, while 'NaN' and '-inf' aren't.
1269
1270=head2 is_negative()
1271
1272 print "$x is < 0\n" if $x->is_negative();
1273
1274Return true if $x is negative (smaller than zero), otherwise false. Please
1275note that '-inf' is also negative, while 'NaN' and '+inf' aren't.
1276
1277=head2 is_int()
1278
1279 print "$x is an integer\n" if $x->is_int();
1280
1281Return true if $x has a denominator of 1 (e.g. no fraction parts), otherwise
1282false. Please note that '-inf', 'inf' and 'NaN' aren't integer.
1283
1284=head2 is_odd()
1285
1286 print "$x is odd\n" if $x->is_odd();
1287
1288Return true if $x is odd, otherwise false.
1289
1290=head2 is_even()
1291
1292 print "$x is even\n" if $x->is_even();
1293
1294Return true if $x is even, otherwise false.
1295
1296=head2 bceil()
1297
1298 $x->bceil();
1299
1300Set $x to the next bigger integer value (e.g. truncate the number to integer
1301and then increment it by one).
1302
1303=head2 bfloor()
1304
1305 $x->bfloor();
1306
1307Truncate $x to an integer value.
6de7f0cc 1308
990fb837 1309=head2 config
1310
1311 use Data::Dumper;
1312
1313 print Dumper ( Math::BigRat->config() );
1314 print Math::BigRat->config()->{lib},"\n";
1315
1316Returns a hash containing the configuration, e.g. the version number, lib
1317loaded etc. The following hash keys are currently filled in with the
1318appropriate information.
1319
1320 key RO/RW Description
1321 Example
1322 ============================================================
1323 lib RO Name of the Math library
1324 Math::BigInt::Calc
1325 lib_version RO Version of 'lib'
1326 0.30
1327 class RO The class of config you just called
1328 Math::BigRat
1329 version RO version number of the class you used
1330 0.10
1331 upgrade RW To which class numbers are upgraded
1332 undef
1333 downgrade RW To which class numbers are downgraded
1334 undef
1335 precision RW Global precision
1336 undef
1337 accuracy RW Global accuracy
1338 undef
1339 round_mode RW Global round mode
1340 even
1341 div_scale RW Fallback acccuracy for div
1342 40
1343 trap_nan RW Trap creation of NaN (undef = no)
1344 undef
1345 trap_inf RW Trap creation of +inf/-inf (undef = no)
1346 undef
1347
1348By passing a reference to a hash you may set the configuration values. This
1349works only for values that a marked with a C<RW> above, anything else is
1350read-only.
1351
a4e2b1c6 1352=head1 BUGS
6de7f0cc 1353
7d341013 1354Some things are not yet implemented, or only implemented half-way:
1355
1356=over 2
1357
1358=item inf handling (partial)
1359
1360=item NaN handling (partial)
1361
1362=item rounding (not implemented except for bceil/bfloor)
1363
1364=item $x ** $y where $y is not an integer
1365
1366=back
184f15d5 1367
1368=head1 LICENSE
1369
1370This program is free software; you may redistribute it and/or modify it under
1371the same terms as Perl itself.
1372
1373=head1 SEE ALSO
1374
1375L<Math::BigFloat> and L<Math::Big> as well as L<Math::BigInt::BitVect>,
1376L<Math::BigInt::Pari> and L<Math::BigInt::GMP>.
1377
7d341013 1378See L<http://search.cpan.org/search?dist=bignum> for a way to use
1379Math::BigRat.
1380
1381The package at L<http://search.cpan.org/search?dist=Math%3A%3ABigRat>
1382may contain more documentation and examples as well as testcases.
184f15d5 1383
1384=head1 AUTHORS
1385
1386(C) by Tels L<http://bloodgate.com/> 2001-2002.
1387
1388=cut