Nicer formatting for function arguments in Carp messages
[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
b1f79218 12# _f : flags, used by MBR to flag parts of a rational 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 {
b1f79218 59 # turn a single float input into a rational (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;
93c87d9d 171 # handle inf and NAN cases:
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 {
b1f79218 368 # add two rationals
7d341013 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 {
b1f79218 413 # subtract two rationals
7d341013 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 {
b1f79218 457 # multiply two rationals
7d341013 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
93c87d9d 573 # locally disable these, since they would interfere
990fb837 574 local $Math::BigInt::upgrade = undef;
575 local $Math::BigInt::accuracy = undef;
576 local $Math::BigInt::precision = undef;
577
578 my $u = $x->copy()->babs();
93c87d9d 579 # first, do a "normal" division ($x/$y)
990fb837 580 $u->{_d}->bmul($y->{_n});
581 $u->{_n}->bmul($y->{_d});
582
583 # compute floor
584 if (!$u->{_d}->is_one())
585 {
586 $u->{_n}->bdiv($u->{_d}); # 22/7 => 3/1 w/ truncate
587 # no need to set $u->{_d} to 1, since later we set it to $y->{_d}
588 #$x->{_n}->binc() if $x->{sign} eq '-'; # -22/7 => -4/1
589 }
590
591 # compute $y * $u
592 $u->{_d} = $y->{_d}; # 1 * $y->{_d}, see floor above
593 $u->{_n}->bmul($y->{_n});
594
595 my $xsign = $x->{sign}; $x->{sign} = '+'; # remember sign and make abs
596 # compute $x - $u
597 $x->bsub($u);
598 $x->{sign} = $xsign; # put sign back
599
600 $x->bnorm()->round(@r);
990fb837 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;
93c87d9d 911 $x->{_d} = Math::BigFloat->new($x->{_d})->bsqrt();
912 $x->{_n} = Math::BigFloat->new($x->{_n})->bsqrt();
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
93c87d9d 924 $x->{_n} = $x->{_n}->{_m}; # 710/45.1 => 710/451
990fb837 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
93c87d9d 1027 # N/1 => N
1028 return $x->{_n}->numify() if $x->{_d}->is_one();
1029
1030 # N/D
1031 my $neg = 1; $neg = -1 if $x->{sign} ne '+';
1032 $neg * $x->{_n}->numify() / $x->{_d}->numify(); # return sign * N/D
7d341013 1033 }
1034
184f15d5 1035sub as_number
1036 {
1037 my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
1038
990fb837 1039 return $x if $x->{sign} !~ /^[+-]$/; # NaN, inf etc
1040
1041 # need to disable these, otherwise bdiv() gives BigRat again
1042 local $Math::BigInt::upgrade = undef;
1043 local $Math::BigInt::accuracy = undef;
1044 local $Math::BigInt::precision = undef;
184f15d5 1045 my $t = $x->{_n}->copy()->bdiv($x->{_d}); # 22/7 => 3
1046 $t->{sign} = $x->{sign};
1047 $t;
1048 }
1049
6de7f0cc 1050sub import
1051 {
1052 my $self = shift;
1053 my $l = scalar @_;
1054 my $lib = ''; my @a;
1055 for ( my $i = 0; $i < $l ; $i++)
1056 {
1057# print "at $_[$i] (",$_[$i+1]||'undef',")\n";
1058 if ( $_[$i] eq ':constant' )
1059 {
1060 # this rest causes overlord er load to step in
1061 # print "overload @_\n";
1062 overload::constant float => sub { $self->new(shift); };
1063 }
1064# elsif ($_[$i] eq 'upgrade')
1065# {
1066# # this causes upgrading
1067# $upgrade = $_[$i+1]; # or undef to disable
1068# $i++;
1069# }
1070 elsif ($_[$i] eq 'downgrade')
1071 {
1072 # this causes downgrading
1073 $downgrade = $_[$i+1]; # or undef to disable
1074 $i++;
1075 }
1076 elsif ($_[$i] eq 'lib')
1077 {
1078 $lib = $_[$i+1] || ''; # default Calc
1079 $i++;
1080 }
1081 elsif ($_[$i] eq 'with')
1082 {
1083 $MBI = $_[$i+1] || 'Math::BigInt'; # default Math::BigInt
1084 $i++;
1085 }
1086 else
1087 {
1088 push @a, $_[$i];
1089 }
1090 }
1091 # let use Math::BigInt lib => 'GMP'; use Math::BigFloat; still work
1092 my $mbilib = eval { Math::BigInt->config()->{lib} };
1093 if ((defined $mbilib) && ($MBI eq 'Math::BigInt'))
1094 {
1095 # MBI already loaded
1096 $MBI->import('lib',"$lib,$mbilib", 'objectify');
1097 }
1098 else
1099 {
a4e2b1c6 1100 # MBI not loaded, or not with "Math::BigInt"
6de7f0cc 1101 $lib .= ",$mbilib" if defined $mbilib;
1102
6de7f0cc 1103 if ($] < 5.006)
1104 {
1105 # Perl < 5.6.0 dies with "out of memory!" when eval() and ':constant' is
1106 # used in the same script, or eval inside import().
1107 my @parts = split /::/, $MBI; # Math::BigInt => Math BigInt
1108 my $file = pop @parts; $file .= '.pm'; # BigInt => BigInt.pm
1109 $file = File::Spec->catfile (@parts, $file);
1110 eval { require $file; $MBI->import( lib => '$lib', 'objectify' ); }
1111 }
1112 else
1113 {
1114 my $rc = "use $MBI lib => '$lib', 'objectify';";
1115 eval $rc;
1116 }
1117 }
93c87d9d 1118 if ($@)
1119 {
1120 require Carp; Carp::croak ("Couldn't load $MBI: $! $@");
1121 }
6de7f0cc 1122
1123 # any non :constant stuff is handled by our parent, Exporter
1124 # even if @_ is empty, to give it a chance
1125 $self->SUPER::import(@a); # for subclasses
1126 $self->export_to_level(1,$self,@a); # need this, too
1127 }
184f15d5 1128
11291;
1130
1131__END__
1132
1133=head1 NAME
1134
b1f79218 1135Math::BigRat - arbitrarily big rationals
184f15d5 1136
1137=head1 SYNOPSIS
1138
7d341013 1139 use Math::BigRat;
184f15d5 1140
7d341013 1141 $x = Math::BigRat->new('3/7'); $x += '5/9';
184f15d5 1142
7d341013 1143 print $x->bstr(),"\n";
1144 print $x ** 2,"\n";
184f15d5 1145
1146=head1 DESCRIPTION
1147
7d341013 1148Math::BigRat complements Math::BigInt and Math::BigFloat by providing support
b1f79218 1149for arbitrarily big rationals.
184f15d5 1150
1151=head2 MATH LIBRARY
1152
1153Math with the numbers is done (by default) by a module called
1154Math::BigInt::Calc. This is equivalent to saying:
1155
1156 use Math::BigRat lib => 'Calc';
1157
1158You can change this by using:
1159
1160 use Math::BigRat lib => 'BitVect';
1161
1162The following would first try to find Math::BigInt::Foo, then
1163Math::BigInt::Bar, and when this also fails, revert to Math::BigInt::Calc:
1164
1165 use Math::BigRat lib => 'Foo,Math::BigInt::Bar';
1166
1167Calc.pm uses as internal format an array of elements of some decimal base
7d341013 1168(usually 1e7, but this might be different for some systems) with the least
184f15d5 1169significant digit first, while BitVect.pm uses a bit vector of base 2, most
1170significant bit first. Other modules might use even different means of
1171representing the numbers. See the respective module documentation for further
1172details.
1173
7d341013 1174Currently the following replacement libraries exist, search for them at CPAN:
1175
1176 Math::BigInt::BitVect
1177 Math::BigInt::GMP
1178 Math::BigInt::Pari
1179 Math::BigInt::FastCalc
1180
184f15d5 1181=head1 METHODS
1182
7d341013 1183Any methods not listed here are dervied from Math::BigFloat (or
6de7f0cc 1184Math::BigInt), so make sure you check these two modules for further
1185information.
1186
1187=head2 new()
184f15d5 1188
1189 $x = Math::BigRat->new('1/3');
1190
1191Create a new Math::BigRat object. Input can come in various forms:
1192
7d341013 1193 $x = Math::BigRat->new(123); # scalars
1194 $x = Math::BigRat->new('123.3'); # float
184f15d5 1195 $x = Math::BigRat->new('1/3'); # simple string
1196 $x = Math::BigRat->new('1 / 3'); # spaced
1197 $x = Math::BigRat->new('1 / 0.1'); # w/ floats
1198 $x = Math::BigRat->new(Math::BigInt->new(3)); # BigInt
1199 $x = Math::BigRat->new(Math::BigFloat->new('3.1')); # BigFloat
6de7f0cc 1200 $x = Math::BigRat->new(Math::BigInt::Lite->new('2')); # BigLite
184f15d5 1201
6de7f0cc 1202=head2 numerator()
184f15d5 1203
1204 $n = $x->numerator();
1205
1206Returns a copy of the numerator (the part above the line) as signed BigInt.
1207
6de7f0cc 1208=head2 denominator()
184f15d5 1209
1210 $d = $x->denominator();
1211
1212Returns a copy of the denominator (the part under the line) as positive BigInt.
1213
6de7f0cc 1214=head2 parts()
184f15d5 1215
1216 ($n,$d) = $x->parts();
1217
1218Return a list consisting of (signed) numerator and (unsigned) denominator as
1219BigInts.
1220
6de7f0cc 1221=head2 as_number()
1222
7d341013 1223 $x = Math::BigRat->new('13/7');
1224 print $x->as_number(),"\n"; # '1'
1225
990fb837 1226Returns a copy of the object as BigInt trunced it to integer.
6de7f0cc 1227
a4e2b1c6 1228=head2 bfac()
6de7f0cc 1229
a4e2b1c6 1230 $x->bfac();
6de7f0cc 1231
a4e2b1c6 1232Calculates the factorial of $x. For instance:
6de7f0cc 1233
a4e2b1c6 1234 print Math::BigRat->new('3/1')->bfac(),"\n"; # 1*2*3
1235 print Math::BigRat->new('5/1')->bfac(),"\n"; # 1*2*3*4*5
184f15d5 1236
7d341013 1237Works currently only for integers.
6de7f0cc 1238
a4e2b1c6 1239=head2 blog()
6de7f0cc 1240
a4e2b1c6 1241Is not yet implemented.
6de7f0cc 1242
a4e2b1c6 1243=head2 bround()/round()/bfround()
6de7f0cc 1244
a4e2b1c6 1245Are not yet implemented.
6de7f0cc 1246
990fb837 1247=head2 bmod()
1248
1249 use Math::BigRat;
1250 my $x = Math::BigRat->new('7/4');
1251 my $y = Math::BigRat->new('4/3');
1252 print $x->bmod($y);
1253
1254Set $x to the remainder of the division of $x by $y.
1255
7d341013 1256=head2 is_one()
1257
1258 print "$x is 1\n" if $x->is_one();
1259
1260Return true if $x is exactly one, otherwise false.
1261
1262=head2 is_zero()
1263
1264 print "$x is 0\n" if $x->is_zero();
1265
1266Return true if $x is exactly zero, otherwise false.
1267
1268=head2 is_positive()
1269
1270 print "$x is >= 0\n" if $x->is_positive();
1271
1272Return true if $x is positive (greater than or equal to zero), otherwise
1273false. Please note that '+inf' is also positive, while 'NaN' and '-inf' aren't.
1274
1275=head2 is_negative()
1276
1277 print "$x is < 0\n" if $x->is_negative();
1278
1279Return true if $x is negative (smaller than zero), otherwise false. Please
1280note that '-inf' is also negative, while 'NaN' and '+inf' aren't.
1281
1282=head2 is_int()
1283
1284 print "$x is an integer\n" if $x->is_int();
1285
1286Return true if $x has a denominator of 1 (e.g. no fraction parts), otherwise
1287false. Please note that '-inf', 'inf' and 'NaN' aren't integer.
1288
1289=head2 is_odd()
1290
1291 print "$x is odd\n" if $x->is_odd();
1292
1293Return true if $x is odd, otherwise false.
1294
1295=head2 is_even()
1296
1297 print "$x is even\n" if $x->is_even();
1298
1299Return true if $x is even, otherwise false.
1300
1301=head2 bceil()
1302
1303 $x->bceil();
1304
1305Set $x to the next bigger integer value (e.g. truncate the number to integer
1306and then increment it by one).
1307
1308=head2 bfloor()
1309
1310 $x->bfloor();
1311
1312Truncate $x to an integer value.
6de7f0cc 1313
990fb837 1314=head2 config
1315
1316 use Data::Dumper;
1317
1318 print Dumper ( Math::BigRat->config() );
1319 print Math::BigRat->config()->{lib},"\n";
1320
1321Returns a hash containing the configuration, e.g. the version number, lib
1322loaded etc. The following hash keys are currently filled in with the
1323appropriate information.
1324
1325 key RO/RW Description
1326 Example
1327 ============================================================
1328 lib RO Name of the Math library
1329 Math::BigInt::Calc
1330 lib_version RO Version of 'lib'
1331 0.30
1332 class RO The class of config you just called
1333 Math::BigRat
1334 version RO version number of the class you used
1335 0.10
1336 upgrade RW To which class numbers are upgraded
1337 undef
1338 downgrade RW To which class numbers are downgraded
1339 undef
1340 precision RW Global precision
1341 undef
1342 accuracy RW Global accuracy
1343 undef
1344 round_mode RW Global round mode
1345 even
1346 div_scale RW Fallback acccuracy for div
1347 40
1348 trap_nan RW Trap creation of NaN (undef = no)
1349 undef
1350 trap_inf RW Trap creation of +inf/-inf (undef = no)
1351 undef
1352
1353By passing a reference to a hash you may set the configuration values. This
1354works only for values that a marked with a C<RW> above, anything else is
1355read-only.
1356
a4e2b1c6 1357=head1 BUGS
6de7f0cc 1358
7d341013 1359Some things are not yet implemented, or only implemented half-way:
1360
1361=over 2
1362
1363=item inf handling (partial)
1364
1365=item NaN handling (partial)
1366
1367=item rounding (not implemented except for bceil/bfloor)
1368
1369=item $x ** $y where $y is not an integer
1370
1371=back
184f15d5 1372
1373=head1 LICENSE
1374
1375This program is free software; you may redistribute it and/or modify it under
1376the same terms as Perl itself.
1377
1378=head1 SEE ALSO
1379
1380L<Math::BigFloat> and L<Math::Big> as well as L<Math::BigInt::BitVect>,
1381L<Math::BigInt::Pari> and L<Math::BigInt::GMP>.
1382
7d341013 1383See L<http://search.cpan.org/search?dist=bignum> for a way to use
1384Math::BigRat.
1385
1386The package at L<http://search.cpan.org/search?dist=Math%3A%3ABigRat>
1387may contain more documentation and examples as well as testcases.
184f15d5 1388
1389=head1 AUTHORS
1390
1391(C) by Tels L<http://bloodgate.com/> 2001-2002.
1392
1393=cut