This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Upgraded Math::BigRat, Math::BigInt::FastCalc, Math::BigInt, & bignum
[perl5.git] / cpan / Math-BigRat / lib / Math / BigRat.pm
CommitLineData
a4e2b1c6 1#
7d341013 2# "Tax the rat farms." - Lord Vetinari
a4e2b1c6 3#
184f15d5
JH
4
5# The following hash values are used:
6# sign : +,-,NaN,+inf,-inf
7# _d : denominator
c4a6f826 8# _n : numerator (value = _n/_d)
184f15d5
JH
9# _a : accuracy
10# _p : precision
7afd7a91 11# You should not look at the innards of a BigRat - use the methods for this.
184f15d5
JH
12
13package Math::BigRat;
14
08a3f4a9 15use 5.006;
184f15d5 16use strict;
11c955be
SH
17use warnings;
18
3cc1ad36 19use Carp qw< carp croak >;
184f15d5 20
92c15a49 21use Math::BigFloat 1.999718;
11c955be 22
7deec013 23our $VERSION = '0.2617';
184f15d5 24
6320cdc0
SH
25our @ISA = qw(Math::BigFloat);
26
27our ($accuracy, $precision, $round_mode, $div_scale,
28 $upgrade, $downgrade, $_trap_nan, $_trap_inf);
9aa0b648
FR
29
30use overload
6320cdc0
SH
31
32 # overload key: with_assign
33
34 '+' => sub { $_[0] -> copy() -> badd($_[1]); },
35
36 '-' => sub { my $c = $_[0] -> copy;
37 $_[2] ? $c -> bneg() -> badd( $_[1])
38 : $c -> bsub($_[1]); },
39
40 '*' => sub { $_[0] -> copy() -> bmul($_[1]); },
41
42 '/' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> bdiv($_[0])
43 : $_[0] -> copy() -> bdiv($_[1]); },
44
6320cdc0
SH
45 '%' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> bmod($_[0])
46 : $_[0] -> copy() -> bmod($_[1]); },
47
48 '**' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> bpow($_[0])
49 : $_[0] -> copy() -> bpow($_[1]); },
50
51 '<<' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> blsft($_[0])
52 : $_[0] -> copy() -> blsft($_[1]); },
53
54 '>>' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> brsft($_[0])
55 : $_[0] -> copy() -> brsft($_[1]); },
56
57 # overload key: assign
58
59 '+=' => sub { $_[0]->badd($_[1]); },
60
61 '-=' => sub { $_[0]->bsub($_[1]); },
62
63 '*=' => sub { $_[0]->bmul($_[1]); },
64
65 '/=' => sub { scalar $_[0]->bdiv($_[1]); },
66
67 '%=' => sub { $_[0]->bmod($_[1]); },
68
69 '**=' => sub { $_[0]->bpow($_[1]); },
70
6320cdc0
SH
71 '<<=' => sub { $_[0]->blsft($_[1]); },
72
73 '>>=' => sub { $_[0]->brsft($_[1]); },
74
75# 'x=' => sub { },
76
77# '.=' => sub { },
78
79 # overload key: num_comparison
80
81 '<' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> blt($_[0])
82 : $_[0] -> blt($_[1]); },
83
84 '<=' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> ble($_[0])
85 : $_[0] -> ble($_[1]); },
86
87 '>' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> bgt($_[0])
88 : $_[0] -> bgt($_[1]); },
89
90 '>=' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> bge($_[0])
91 : $_[0] -> bge($_[1]); },
92
93 '==' => sub { $_[0] -> beq($_[1]); },
94
95 '!=' => sub { $_[0] -> bne($_[1]); },
96
97 # overload key: 3way_comparison
98
99 '<=>' => sub { my $cmp = $_[0] -> bcmp($_[1]);
100 defined($cmp) && $_[2] ? -$cmp : $cmp; },
101
102 'cmp' => sub { $_[2] ? "$_[1]" cmp $_[0] -> bstr()
103 : $_[0] -> bstr() cmp "$_[1]"; },
104
105 # overload key: str_comparison
106
107# 'lt' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> bstrlt($_[0])
108# : $_[0] -> bstrlt($_[1]); },
109#
110# 'le' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> bstrle($_[0])
111# : $_[0] -> bstrle($_[1]); },
112#
113# 'gt' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> bstrgt($_[0])
114# : $_[0] -> bstrgt($_[1]); },
115#
116# 'ge' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> bstrge($_[0])
117# : $_[0] -> bstrge($_[1]); },
118#
119# 'eq' => sub { $_[0] -> bstreq($_[1]); },
120#
121# 'ne' => sub { $_[0] -> bstrne($_[1]); },
122
123 # overload key: binary
124
125 '&' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> band($_[0])
126 : $_[0] -> copy() -> band($_[1]); },
127
128 '&=' => sub { $_[0] -> band($_[1]); },
129
130 '|' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> bior($_[0])
131 : $_[0] -> copy() -> bior($_[1]); },
132
133 '|=' => sub { $_[0] -> bior($_[1]); },
134
135 '^' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> bxor($_[0])
136 : $_[0] -> copy() -> bxor($_[1]); },
137
138 '^=' => sub { $_[0] -> bxor($_[1]); },
139
140# '&.' => sub { },
141
142# '&.=' => sub { },
143
144# '|.' => sub { },
145
146# '|.=' => sub { },
147
148# '^.' => sub { },
149
150# '^.=' => sub { },
151
152 # overload key: unary
153
154 'neg' => sub { $_[0] -> copy() -> bneg(); },
155
156# '!' => sub { },
157
158 '~' => sub { $_[0] -> copy() -> bnot(); },
159
160# '~.' => sub { },
161
162 # overload key: mutators
163
164 '++' => sub { $_[0] -> binc() },
165
166 '--' => sub { $_[0] -> bdec() },
167
168 # overload key: func
169
170 'atan2' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> batan2($_[0])
171 : $_[0] -> copy() -> batan2($_[1]); },
172
173 'cos' => sub { $_[0] -> copy() -> bcos(); },
174
175 'sin' => sub { $_[0] -> copy() -> bsin(); },
176
177 'exp' => sub { $_[0] -> copy() -> bexp($_[1]); },
178
179 'abs' => sub { $_[0] -> copy() -> babs(); },
180
181 'log' => sub { $_[0] -> copy() -> blog(); },
182
183 'sqrt' => sub { $_[0] -> copy() -> bsqrt(); },
184
185 'int' => sub { $_[0] -> copy() -> bint(); },
186
187 # overload key: conversion
188
189 'bool' => sub { $_[0] -> is_zero() ? '' : 1; },
190
191 '""' => sub { $_[0] -> bstr(); },
192
193 '0+' => sub { $_[0] -> numify(); },
194
195 '=' => sub { $_[0]->copy(); },
196
197 ;
11c955be
SH
198
199BEGIN {
200 *objectify = \&Math::BigInt::objectify; # inherit this from BigInt
201 *AUTOLOAD = \&Math::BigFloat::AUTOLOAD; # can't inherit AUTOLOAD
0c2fbbe3
CBW
202 # We inherit these from BigFloat because currently it is not possible that
203 # Math::BigFloat has a different $LIB variable than we, because
204 # Math::BigFloat also uses Math::BigInt::config->('lib') (there is always
205 # only one library loaded)
11c955be
SH
206 *_e_add = \&Math::BigFloat::_e_add;
207 *_e_sub = \&Math::BigFloat::_e_sub;
3cc1ad36 208 *as_number = \&as_int;
11c955be
SH
209 *is_pos = \&is_positive;
210 *is_neg = \&is_negative;
211}
9b924220 212
184f15d5 213##############################################################################
12fc2493 214# Global constants and flags. Access these only via the accessor methods!
184f15d5 215
6320cdc0 216$accuracy = $precision = undef;
184f15d5 217$round_mode = 'even';
6320cdc0
SH
218$div_scale = 40;
219$upgrade = undef;
220$downgrade = undef;
184f15d5 221
12fc2493 222# These are internally, and not to be used from the outside at all!
990fb837
RGS
223
224$_trap_nan = 0; # are NaNs ok? set w/ config()
225$_trap_inf = 0; # are infs ok? set w/ config()
226
3cc1ad36 227# the math backend library
6320cdc0 228
0c2fbbe3 229my $LIB = 'Math::BigInt::Calc';
12fc2493 230
11c955be 231my $nan = 'NaN';
6320cdc0 232#my $class = 'Math::BigRat';
184f15d5 233
11c955be 234sub isa {
6320cdc0 235 return 0 if $_[1] =~ /^Math::Big(Int|Float)/; # we aren't
11c955be
SH
236 UNIVERSAL::isa(@_);
237}
8f675a64 238
12fc2493 239##############################################################################
9b924220 240
6320cdc0
SH
241sub new {
242 my $proto = shift;
243 my $protoref = ref $proto;
244 my $class = $protoref || $proto;
184f15d5 245
6320cdc0 246 # Check the way we are called.
184f15d5 247
6320cdc0 248 if ($protoref) {
3cc1ad36 249 croak("new() is a class method, not an instance method");
184f15d5 250 }
6320cdc0
SH
251
252 if (@_ < 1) {
3cc1ad36 253 #carp("Using new() with no argument is deprecated;",
6320cdc0
SH
254 # " use bzero() or new(0) instead");
255 return $class -> bzero();
184f15d5 256 }
184f15d5 257
6320cdc0 258 if (@_ > 2) {
3cc1ad36 259 carp("Superfluous arguments to new() ignored.");
6320cdc0 260 }
184f15d5 261
6320cdc0
SH
262 # Get numerator and denominator. If any of the arguments is undefined,
263 # return zero.
184f15d5 264
6320cdc0 265 my ($n, $d) = @_;
ccbfef19 266
6320cdc0
SH
267 if (@_ == 1 && !defined $n ||
268 @_ == 2 && (!defined $n || !defined $d))
269 {
3cc1ad36 270 #carp("Use of uninitialized value in new()");
6320cdc0
SH
271 return $class -> bzero();
272 }
b68b7ab1 273
6320cdc0 274 # Initialize a new object.
184f15d5 275
6320cdc0 276 my $self = bless {}, $class;
11c955be 277
6320cdc0 278 # One or two input arguments may be given. First handle the numerator $n.
11c955be 279
6320cdc0
SH
280 if (ref($n)) {
281 $n = Math::BigFloat -> new($n, undef, undef)
282 unless ($n -> isa('Math::BigRat') ||
283 $n -> isa('Math::BigInt') ||
284 $n -> isa('Math::BigFloat'));
285 } else {
286 if (defined $d) {
287 # If the denominator is defined, the numerator is not a string
288 # fraction, e.g., "355/113".
289 $n = Math::BigFloat -> new($n, undef, undef);
290 } else {
291 # If the denominator is undefined, the numerator might be a string
292 # fraction, e.g., "355/113".
293 if ($n =~ m| ^ \s* (\S+) \s* / \s* (\S+) \s* $ |x) {
294 $n = Math::BigFloat -> new($1, undef, undef);
295 $d = Math::BigFloat -> new($2, undef, undef);
296 } else {
297 $n = Math::BigFloat -> new($n, undef, undef);
298 }
299 }
300 }
11c955be 301
6320cdc0
SH
302 # At this point $n is an object and $d is either an object or undefined. An
303 # undefined $d means that $d was not specified by the caller (not that $d
304 # was specified as an undefined value).
11c955be 305
6320cdc0
SH
306 unless (defined $d) {
307 #return $n -> copy($n) if $n -> isa('Math::BigRat');
308 return $class -> copy($n) if $n -> isa('Math::BigRat');
309 return $class -> bnan() if $n -> is_nan();
310 return $class -> binf($n -> sign()) if $n -> is_inf();
11c955be 311
6320cdc0 312 if ($n -> isa('Math::BigInt')) {
0c2fbbe3
CBW
313 $self -> {_n} = $LIB -> _new($n -> copy() -> babs() -> bstr());
314 $self -> {_d} = $LIB -> _one();
6320cdc0
SH
315 $self -> {sign} = $n -> sign();
316 return $self;
11c955be 317 }
6320cdc0
SH
318
319 if ($n -> isa('Math::BigFloat')) {
320 my $m = $n -> mantissa() -> babs();
321 my $e = $n -> exponent();
0c2fbbe3
CBW
322 $self -> {_n} = $LIB -> _new($m -> bstr());
323 $self -> {_d} = $LIB -> _one();
6320cdc0
SH
324
325 if ($e > 0) {
0c2fbbe3
CBW
326 $self -> {_n} = $LIB -> _lsft($self -> {_n},
327 $LIB -> _new($e -> bstr()), 10);
6320cdc0 328 } elsif ($e < 0) {
0c2fbbe3
CBW
329 $self -> {_d} = $LIB -> _lsft($self -> {_d},
330 $LIB -> _new(-$e -> bstr()), 10);
6320cdc0 331
0c2fbbe3
CBW
332 my $gcd = $LIB -> _gcd($LIB -> _copy($self -> {_n}), $self -> {_d});
333 if (!$LIB -> _is_one($gcd)) {
334 $self -> {_n} = $LIB -> _div($self->{_n}, $gcd);
335 $self -> {_d} = $LIB -> _div($self->{_d}, $gcd);
6320cdc0
SH
336 }
337 }
338
339 $self -> {sign} = $n -> sign();
340 return $self;
11c955be 341 }
6320cdc0
SH
342
343 die "I don't know how to handle this"; # should never get here
184f15d5 344 }
12fc2493 345
6320cdc0
SH
346 # At the point we know that both $n and $d are defined. We know that $n is
347 # an object, but $d might still be a scalar. Now handle $d.
11c955be 348
6320cdc0
SH
349 $d = Math::BigFloat -> new($d, undef, undef)
350 unless ref($d) && ($d -> isa('Math::BigRat') ||
351 $d -> isa('Math::BigInt') ||
352 $d -> isa('Math::BigFloat'));
12fc2493 353
6320cdc0
SH
354 # At this point both $n and $d are objects.
355
356 return $class -> bnan() if $n -> is_nan() || $d -> is_nan();
357
358 # At this point neither $n nor $d is a NaN.
12fc2493 359
6320cdc0
SH
360 if ($n -> is_zero()) {
361 return $class -> bnan() if $d -> is_zero(); # 0/0 = NaN
362 return $class -> bzero();
11c955be
SH
363 }
364
6320cdc0 365 return $class -> binf($d -> sign()) if $d -> is_zero();
11c955be 366
6320cdc0
SH
367 # At this point, neither $n nor $d is a NaN or a zero.
368
7deec013
NB
369 # Copy them now before manipulating them.
370
371 $n = $n -> copy();
372 $d = $d -> copy();
373
6320cdc0
SH
374 if ($d < 0) { # make sure denominator is positive
375 $n -> bneg();
376 $d -> bneg();
11c955be
SH
377 }
378
6320cdc0
SH
379 if ($n -> is_inf()) {
380 return $class -> bnan() if $d -> is_inf(); # Inf/Inf = NaN
381 return $class -> binf($n -> sign());
382 }
11c955be 383
6320cdc0 384 # At this point $n is finite.
11c955be 385
6320cdc0
SH
386 return $class -> bzero() if $d -> is_inf();
387 return $class -> binf($d -> sign()) if $d -> is_zero();
11c955be 388
6320cdc0 389 # At this point both $n and $d are finite and non-zero.
990fb837 390
6320cdc0
SH
391 if ($n < 0) {
392 $n -> bneg();
393 $self -> {sign} = '-';
394 } else {
395 $self -> {sign} = '+';
11c955be
SH
396 }
397
6320cdc0
SH
398 if ($n -> isa('Math::BigRat')) {
399
400 if ($d -> isa('Math::BigRat')) {
401
402 # At this point both $n and $d is a Math::BigRat.
403
404 # p r p * s (p / gcd(p, r)) * (s / gcd(s, q))
405 # - / - = ----- = ---------------------------------
406 # q s q * r (q / gcd(s, q)) * (r / gcd(p, r))
407
408 my $p = $n -> {_n};
409 my $q = $n -> {_d};
410 my $r = $d -> {_n};
411 my $s = $d -> {_d};
0c2fbbe3
CBW
412 my $gcd_pr = $LIB -> _gcd($LIB -> _copy($p), $r);
413 my $gcd_sq = $LIB -> _gcd($LIB -> _copy($s), $q);
414 $self -> {_n} = $LIB -> _mul($LIB -> _div($LIB -> _copy($p), $gcd_pr),
415 $LIB -> _div($LIB -> _copy($s), $gcd_sq));
416 $self -> {_d} = $LIB -> _mul($LIB -> _div($LIB -> _copy($q), $gcd_sq),
417 $LIB -> _div($LIB -> _copy($r), $gcd_pr));
6320cdc0
SH
418
419 return $self; # no need for $self -> bnorm() here
11c955be 420 }
6320cdc0
SH
421
422 # At this point, $n is a Math::BigRat and $d is a Math::Big(Int|Float).
423
424 my $p = $n -> {_n};
425 my $q = $n -> {_d};
426 my $m = $d -> mantissa();
427 my $e = $d -> exponent();
428
429 # / p
430 # | ------------ if e > 0
431 # | q * m * 10^e
432 # |
433 # p | p
434 # - / (m * 10^e) = | ----- if e == 0
435 # q | q * m
436 # |
437 # | p * 10^-e
438 # | -------- if e < 0
439 # \ q * m
440
0c2fbbe3
CBW
441 $self -> {_n} = $LIB -> _copy($p);
442 $self -> {_d} = $LIB -> _mul($LIB -> _copy($q), $m);
6320cdc0 443 if ($e > 0) {
0c2fbbe3 444 $self -> {_d} = $LIB -> _lsft($self -> {_d}, $e, 10);
6320cdc0 445 } elsif ($e < 0) {
0c2fbbe3 446 $self -> {_n} = $LIB -> _lsft($self -> {_n}, -$e, 10);
11c955be 447 }
184f15d5 448
6320cdc0
SH
449 return $self -> bnorm();
450
451 } else {
452
453 if ($d -> isa('Math::BigRat')) {
454
455 # At this point $n is a Math::Big(Int|Float) and $d is a
456 # Math::BigRat.
457
458 my $m = $n -> mantissa();
459 my $e = $n -> exponent();
460 my $p = $d -> {_n};
461 my $q = $d -> {_d};
462
463 # / q * m * 10^e
464 # | ------------ if e > 0
465 # | p
466 # |
467 # p | m * q
468 # (m * 10^e) / - = | ----- if e == 0
469 # q | p
470 # |
471 # | q * m
472 # | --------- if e < 0
473 # \ p * 10^-e
474
0c2fbbe3
CBW
475 $self -> {_n} = $LIB -> _mul($LIB -> _copy($q), $m);
476 $self -> {_d} = $LIB -> _copy($p);
6320cdc0 477 if ($e > 0) {
0c2fbbe3 478 $self -> {_n} = $LIB -> _lsft($self -> {_n}, $e, 10);
6320cdc0 479 } elsif ($e < 0) {
0c2fbbe3 480 $self -> {_d} = $LIB -> _lsft($self -> {_d}, -$e, 10);
6320cdc0
SH
481 }
482 return $self -> bnorm();
483
484 } else {
485
486 # At this point $n and $d are both a Math::Big(Int|Float)
487
488 my $m1 = $n -> mantissa();
489 my $e1 = $n -> exponent();
490 my $m2 = $d -> mantissa();
491 my $e2 = $d -> exponent();
492
493 # /
494 # | m1 * 10^(e1 - e2)
495 # | ----------------- if e1 > e2
496 # | m2
497 # |
498 # m1 * 10^e1 | m1
499 # ---------- = | -- if e1 = e2
500 # m2 * 10^e2 | m2
501 # |
502 # | m1
503 # | ----------------- if e1 < e2
504 # | m2 * 10^(e2 - e1)
505 # \
506
0c2fbbe3
CBW
507 $self -> {_n} = $LIB -> _new($m1 -> bstr());
508 $self -> {_d} = $LIB -> _new($m2 -> bstr());
6320cdc0
SH
509 my $ediff = $e1 - $e2;
510 if ($ediff > 0) {
0c2fbbe3
CBW
511 $self -> {_n} = $LIB -> _lsft($self -> {_n},
512 $LIB -> _new($ediff -> bstr()),
6320cdc0
SH
513 10);
514 } elsif ($ediff < 0) {
0c2fbbe3
CBW
515 $self -> {_d} = $LIB -> _lsft($self -> {_d},
516 $LIB -> _new(-$ediff -> bstr()),
6320cdc0
SH
517 10);
518 }
519
520 return $self -> bnorm();
11c955be 521 }
184f15d5 522 }
184f15d5 523
6320cdc0 524 return $self;
11c955be 525}
b68b7ab1 526
11c955be
SH
527sub copy {
528 my $self = shift;
529 my $selfref = ref $self;
530 my $class = $selfref || $self;
9b924220 531
11c955be 532 # If called as a class method, the object to copy is the next argument.
9b924220 533
11c955be
SH
534 $self = shift() unless $selfref;
535
536 my $copy = bless {}, $class;
537
538 $copy->{sign} = $self->{sign};
0c2fbbe3
CBW
539 $copy->{_d} = $LIB->_copy($self->{_d});
540 $copy->{_n} = $LIB->_copy($self->{_n});
11c955be
SH
541 $copy->{_a} = $self->{_a} if defined $self->{_a};
542 $copy->{_p} = $self->{_p} if defined $self->{_p};
543
6320cdc0
SH
544 #($copy, $copy->{_a}, $copy->{_p})
545 # = $copy->_find_round_parameters(@_);
546
547 return $copy;
548}
549
550sub bnan {
551 my $self = shift;
552 my $selfref = ref $self;
553 my $class = $selfref || $self;
554
555 $self = bless {}, $class unless $selfref;
556
557 if ($_trap_nan) {
3cc1ad36 558 croak ("Tried to set a variable to NaN in $class->bnan()");
6320cdc0
SH
559 }
560
561 $self -> {sign} = $nan;
0c2fbbe3
CBW
562 $self -> {_n} = $LIB -> _zero();
563 $self -> {_d} = $LIB -> _one();
6320cdc0
SH
564
565 ($self, $self->{_a}, $self->{_p})
566 = $self->_find_round_parameters(@_);
567
568 return $self;
569}
570
571sub binf {
572 my $self = shift;
573 my $selfref = ref $self;
574 my $class = $selfref || $self;
575
576 $self = bless {}, $class unless $selfref;
577
578 my $sign = shift();
579 $sign = defined($sign) && substr($sign, 0, 1) eq '-' ? '-inf' : '+inf';
580
581 if ($_trap_inf) {
3cc1ad36 582 croak ("Tried to set a variable to +-inf in $class->binf()");
6320cdc0
SH
583 }
584
585 $self -> {sign} = $sign;
0c2fbbe3
CBW
586 $self -> {_n} = $LIB -> _zero();
587 $self -> {_d} = $LIB -> _one();
6320cdc0
SH
588
589 ($self, $self->{_a}, $self->{_p})
590 = $self->_find_round_parameters(@_);
591
592 return $self;
593}
594
595sub bone {
596 my $self = shift;
597 my $selfref = ref $self;
598 my $class = $selfref || $self;
599
600 $self = bless {}, $class unless $selfref;
601
602 my $sign = shift();
603 $sign = '+' unless defined($sign) && $sign eq '-';
604
605 $self -> {sign} = $sign;
0c2fbbe3
CBW
606 $self -> {_n} = $LIB -> _one();
607 $self -> {_d} = $LIB -> _one();
6320cdc0
SH
608
609 ($self, $self->{_a}, $self->{_p})
610 = $self->_find_round_parameters(@_);
611
612 return $self;
613}
614
615sub bzero {
616 my $self = shift;
617 my $selfref = ref $self;
618 my $class = $selfref || $self;
619
620 $self = bless {}, $class unless $selfref;
621
622 $self -> {sign} = '+';
0c2fbbe3
CBW
623 $self -> {_n} = $LIB -> _zero();
624 $self -> {_d} = $LIB -> _one();
6320cdc0
SH
625
626 ($self, $self->{_a}, $self->{_p})
627 = $self->_find_round_parameters(@_);
628
629 return $self;
11c955be 630}
9b924220 631
990fb837
RGS
632##############################################################################
633
6320cdc0
SH
634sub config {
635 # return (later set?) configuration data as hash ref
636 my $class = shift() || 'Math::BigRat';
990fb837 637
6320cdc0
SH
638 if (@_ == 1 && ref($_[0]) ne 'HASH') {
639 my $cfg = $class->SUPER::config();
640 return $cfg->{$_[0]};
116a1b2f
SP
641 }
642
6320cdc0 643 my $cfg = $class->SUPER::config(@_);
990fb837 644
6320cdc0
SH
645 # now we need only to override the ones that are different from our parent
646 $cfg->{class} = $class;
0c2fbbe3 647 $cfg->{with} = $LIB;
6320cdc0
SH
648
649 $cfg;
650}
990fb837
RGS
651
652##############################################################################
8f675a64 653
6320cdc0
SH
654sub bstr {
655 my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
184f15d5 656
6320cdc0
SH
657 if ($x->{sign} !~ /^[+-]$/) { # inf, NaN etc
658 my $s = $x->{sign};
659 $s =~ s/^\+//; # +inf => inf
660 return $s;
184f15d5
JH
661 }
662
6320cdc0
SH
663 my $s = '';
664 $s = $x->{sign} if $x->{sign} ne '+'; # '+3/2' => '3/2'
184f15d5 665
0c2fbbe3
CBW
666 return $s . $LIB->_str($x->{_n}) if $LIB->_is_one($x->{_d});
667 $s . $LIB->_str($x->{_n}) . '/' . $LIB->_str($x->{_d});
6320cdc0 668}
184f15d5 669
6320cdc0
SH
670sub bsstr {
671 my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
184f15d5 672
6320cdc0 673 if ($x->{sign} !~ /^[+-]$/) { # inf, NaN etc
15f1cdaa 674 my $s = $x->{sign};
6320cdc0
SH
675 $s =~ s/^\+//; # +inf => inf
676 return $s;
184f15d5 677 }
ccbfef19 678
6320cdc0
SH
679 my $s = '';
680 $s = $x->{sign} if $x->{sign} ne '+'; # +3 vs 3
0c2fbbe3 681 $s . $LIB->_str($x->{_n}) . '/' . $LIB->_str($x->{_d});
6320cdc0 682}
184f15d5 683
6320cdc0
SH
684sub bnorm {
685 # reduce the number to the shortest form
686 my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
184f15d5 687
6320cdc0 688 # Both parts must be objects of whatever we are using today.
0c2fbbe3 689 if (my $c = $LIB->_check($x->{_n})) {
3cc1ad36 690 croak("n did not pass the self-check ($c) in bnorm()");
990fb837 691 }
0c2fbbe3 692 if (my $c = $LIB->_check($x->{_d})) {
3cc1ad36 693 croak("d did not pass the self-check ($c) in bnorm()");
990fb837 694 }
6de7f0cc 695
6320cdc0
SH
696 # no normalize for NaN, inf etc.
697 return $x if $x->{sign} !~ /^[+-]$/;
6de7f0cc 698
6320cdc0 699 # normalize zeros to 0/1
0c2fbbe3 700 if ($LIB->_is_zero($x->{_n})) {
6320cdc0 701 $x->{sign} = '+'; # never leave a -0
0c2fbbe3 702 $x->{_d} = $LIB->_one() unless $LIB->_is_one($x->{_d});
6320cdc0 703 return $x;
184f15d5
JH
704 }
705
0c2fbbe3 706 return $x if $LIB->_is_one($x->{_d}); # no need to reduce
6de7f0cc 707
6320cdc0 708 # Compute the GCD.
0c2fbbe3
CBW
709 my $gcd = $LIB->_gcd($LIB->_copy($x->{_n}), $x->{_d});
710 if (!$LIB->_is_one($gcd)) {
711 $x->{_n} = $LIB->_div($x->{_n}, $gcd);
712 $x->{_d} = $LIB->_div($x->{_d}, $gcd);
184f15d5 713 }
6320cdc0
SH
714
715 $x;
716}
184f15d5
JH
717
718##############################################################################
b68b7ab1
T
719# sign manipulation
720
6320cdc0
SH
721sub bneg {
722 # (BRAT or num_str) return BRAT
723 # negate number or make a negated number from string
724 my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
b68b7ab1 725
6320cdc0 726 return $x if $x->modify('bneg');
b68b7ab1 727
6320cdc0
SH
728 # for +0 do not negate (to have always normalized +0). Does nothing for 'NaN'
729 $x->{sign} =~ tr/+-/-+/
0c2fbbe3 730 unless ($x->{sign} eq '+' && $LIB->_is_zero($x->{_n}));
6320cdc0
SH
731 $x;
732}
b68b7ab1
T
733
734##############################################################################
184f15d5
JH
735# special values
736
6320cdc0
SH
737sub _bnan {
738 # used by parent class bnan() to initialize number to NaN
739 my $self = shift;
990fb837 740
6320cdc0
SH
741 if ($_trap_nan) {
742 my $class = ref($self);
743 # "$self" below will stringify the object, this blows up if $self is a
744 # partial object (happens under trap_nan), so fix it beforehand
0c2fbbe3
CBW
745 $self->{_d} = $LIB->_zero() unless defined $self->{_d};
746 $self->{_n} = $LIB->_zero() unless defined $self->{_n};
3cc1ad36 747 croak ("Tried to set $self to NaN in $class\::_bnan()");
990fb837 748 }
0c2fbbe3
CBW
749 $self->{_n} = $LIB->_zero();
750 $self->{_d} = $LIB->_zero();
6320cdc0 751}
184f15d5 752
6320cdc0
SH
753sub _binf {
754 # used by parent class bone() to initialize number to +inf/-inf
755 my $self = shift;
990fb837 756
6320cdc0
SH
757 if ($_trap_inf) {
758 my $class = ref($self);
759 # "$self" below will stringify the object, this blows up if $self is a
760 # partial object (happens under trap_nan), so fix it beforehand
0c2fbbe3
CBW
761 $self->{_d} = $LIB->_zero() unless defined $self->{_d};
762 $self->{_n} = $LIB->_zero() unless defined $self->{_n};
3cc1ad36 763 croak ("Tried to set $self to inf in $class\::_binf()");
990fb837 764 }
0c2fbbe3
CBW
765 $self->{_n} = $LIB->_zero();
766 $self->{_d} = $LIB->_zero();
6320cdc0
SH
767}
768
769sub _bone {
770 # used by parent class bone() to initialize number to +1/-1
771 my $self = shift;
0c2fbbe3
CBW
772 $self->{_n} = $LIB->_one();
773 $self->{_d} = $LIB->_one();
6320cdc0
SH
774}
775
776sub _bzero {
777 # used by parent class bzero() to initialize number to 0
778 my $self = shift;
0c2fbbe3
CBW
779 $self->{_n} = $LIB->_zero();
780 $self->{_d} = $LIB->_one();
6320cdc0 781}
184f15d5
JH
782
783##############################################################################
784# mul/add/div etc
785
6320cdc0
SH
786sub badd {
787 # add two rational numbers
7d341013 788
6320cdc0
SH
789 # set up parameters
790 my ($class, $x, $y, @r) = (ref($_[0]), @_);
791 # objectify is costly, so avoid it
792 if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) {
793 ($class, $x, $y, @r) = objectify(2, @_);
7d341013 794 }
184f15d5 795
6320cdc0
SH
796 # +inf + +inf => +inf, -inf + -inf => -inf
797 return $x->binf(substr($x->{sign}, 0, 1))
798 if $x->{sign} eq $y->{sign} && $x->{sign} =~ /^[+-]inf$/;
184f15d5 799
6320cdc0
SH
800 # +inf + -inf or -inf + +inf => NaN
801 return $x->bnan() if ($x->{sign} !~ /^[+-]$/ || $y->{sign} !~ /^[+-]$/);
184f15d5 802
6320cdc0
SH
803 # 1 1 gcd(3, 4) = 1 1*3 + 1*4 7
804 # - + - = --------- = --
805 # 4 3 4*3 12
184f15d5 806
6320cdc0
SH
807 # we do not compute the gcd() here, but simple do:
808 # 5 7 5*3 + 7*4 43
809 # - + - = --------- = --
810 # 4 3 4*3 12
ccbfef19 811
6320cdc0 812 # and bnorm() will then take care of the rest
184f15d5 813
6320cdc0 814 # 5 * 3
0c2fbbe3 815 $x->{_n} = $LIB->_mul($x->{_n}, $y->{_d});
7d341013 816
6320cdc0 817 # 7 * 4
0c2fbbe3 818 my $m = $LIB->_mul($LIB->_copy($y->{_n}), $x->{_d});
184f15d5 819
6320cdc0
SH
820 # 5 * 3 + 7 * 4
821 ($x->{_n}, $x->{sign}) = _e_add($x->{_n}, $m, $x->{sign}, $y->{sign});
184f15d5 822
6320cdc0 823 # 4 * 3
0c2fbbe3 824 $x->{_d} = $LIB->_mul($x->{_d}, $y->{_d});
184f15d5 825
6320cdc0
SH
826 # normalize result, and possible round
827 $x->bnorm()->round(@r);
828}
184f15d5 829
6320cdc0
SH
830sub bsub {
831 # subtract two rational numbers
7d341013 832
6320cdc0
SH
833 # set up parameters
834 my ($class, $x, $y, @r) = (ref($_[0]), @_);
835 # objectify is costly, so avoid it
836 if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) {
837 ($class, $x, $y, @r) = objectify(2, @_);
7d341013 838 }
184f15d5 839
6320cdc0
SH
840 # flip sign of $x, call badd(), then flip sign of result
841 $x->{sign} =~ tr/+-/-+/
0c2fbbe3 842 unless $x->{sign} eq '+' && $LIB->_is_zero($x->{_n}); # not -0
6320cdc0
SH
843 $x->badd($y, @r); # does norm and round
844 $x->{sign} =~ tr/+-/-+/
0c2fbbe3 845 unless $x->{sign} eq '+' && $LIB->_is_zero($x->{_n}); # not -0
6320cdc0
SH
846
847 $x;
848}
849
850sub bmul {
851 # multiply two rational numbers
852
853 # set up parameters
854 my ($class, $x, $y, @r) = (ref($_[0]), @_);
855 # objectify is costly, so avoid it
856 if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) {
857 ($class, $x, $y, @r) = objectify(2, @_);
7d341013 858 }
184f15d5 859
0c2fbbe3 860 return $x->bnan() if $x->{sign} eq 'NaN' || $y->{sign} eq 'NaN';
184f15d5 861
6320cdc0 862 # inf handling
0c2fbbe3 863 if ($x->{sign} =~ /^[+-]inf$/ || $y->{sign} =~ /^[+-]inf$/) {
6320cdc0
SH
864 return $x->bnan() if $x->is_zero() || $y->is_zero();
865 # result will always be +-inf:
866 # +inf * +/+inf => +inf, -inf * -/-inf => +inf
867 # +inf * -/-inf => -inf, -inf * +/+inf => -inf
868 return $x->binf() if ($x->{sign} =~ /^\+/ && $y->{sign} =~ /^\+/);
869 return $x->binf() if ($x->{sign} =~ /^-/ && $y->{sign} =~ /^-/);
870 return $x->binf('-');
184f15d5
JH
871 }
872
0c2fbbe3
CBW
873 # x == 0 # also: or y == 1 or y == -1
874 return wantarray ? ($x, $class->bzero()) : $x if $x -> is_zero();
184f15d5 875
0c2fbbe3
CBW
876 if ($y -> is_zero()) {
877 $x -> bzero();
878 return wantarray ? ($x, $class->bzero()) : $x;
879 }
184f15d5 880
0c2fbbe3
CBW
881 # According to Knuth, this can be optimized by doing gcd twice (for d
882 # and n) and reducing in one step. This saves us a bnorm() at the end.
883 #
884 # p s p * s (p / gcd(p, r)) * (s / gcd(s, q))
885 # - * - = ----- = ---------------------------------
886 # q r q * r (q / gcd(s, q)) * (r / gcd(p, r))
ccbfef19 887
0c2fbbe3
CBW
888 my $gcd_pr = $LIB -> _gcd($LIB -> _copy($x->{_n}), $y->{_d});
889 my $gcd_sq = $LIB -> _gcd($LIB -> _copy($y->{_n}), $x->{_d});
890
891 $x->{_n} = $LIB -> _mul(scalar $LIB -> _div($x->{_n}, $gcd_pr),
92c15a49
EH
892 scalar $LIB -> _div($LIB -> _copy($y->{_n}),
893 $gcd_sq));
0c2fbbe3 894 $x->{_d} = $LIB -> _mul(scalar $LIB -> _div($x->{_d}, $gcd_sq),
92c15a49
EH
895 scalar $LIB -> _div($LIB -> _copy($y->{_d}),
896 $gcd_pr));
184f15d5 897
6320cdc0
SH
898 # compute new sign
899 $x->{sign} = $x->{sign} eq $y->{sign} ? '+' : '-';
184f15d5 900
0c2fbbe3 901 $x->round(@r);
6320cdc0 902}
184f15d5 903
6320cdc0
SH
904sub bdiv {
905 # (dividend: BRAT or num_str, divisor: BRAT or num_str) return
906 # (BRAT, BRAT) (quo, rem) or BRAT (only rem)
7d341013 907
6320cdc0
SH
908 # set up parameters
909 my ($class, $x, $y, @r) = (ref($_[0]), @_);
910 # objectify is costly, so avoid it
911 if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) {
912 ($class, $x, $y, @r) = objectify(2, @_);
7d341013 913 }
184f15d5 914
6320cdc0 915 return $x if $x->modify('bdiv');
184f15d5 916
6320cdc0 917 my $wantarray = wantarray; # call only once
3f185657
PJA
918
919 # At least one argument is NaN. This is handled the same way as in
920 # Math::BigInt -> bdiv(). See the comments in the code implementing that
921 # method.
922
923 if ($x -> is_nan() || $y -> is_nan()) {
6320cdc0 924 return $wantarray ? ($x -> bnan(), $class -> bnan()) : $x -> bnan();
3f185657
PJA
925 }
926
927 # Divide by zero and modulo zero. This is handled the same way as in
928 # Math::BigInt -> bdiv(). See the comments in the code implementing that
929 # method.
930
931 if ($y -> is_zero()) {
932 my ($quo, $rem);
933 if ($wantarray) {
934 $rem = $x -> copy();
935 }
936 if ($x -> is_zero()) {
937 $quo = $x -> bnan();
938 } else {
939 $quo = $x -> binf($x -> {sign});
940 }
941 return $wantarray ? ($quo, $rem) : $quo;
942 }
943
944 # Numerator (dividend) is +/-inf. This is handled the same way as in
945 # Math::BigInt -> bdiv(). See the comments in the code implementing that
946 # method.
947
948 if ($x -> is_inf()) {
949 my ($quo, $rem);
6320cdc0 950 $rem = $class -> bnan() if $wantarray;
3f185657
PJA
951 if ($y -> is_inf()) {
952 $quo = $x -> bnan();
953 } else {
954 my $sign = $x -> bcmp(0) == $y -> bcmp(0) ? '+' : '-';
955 $quo = $x -> binf($sign);
956 }
6320cdc0
SH
957 return $wantarray ? ($quo, $rem) : $quo;
958 }
959
960 # Denominator (divisor) is +/-inf. This is handled the same way as in
961 # Math::BigFloat -> bdiv(). See the comments in the code implementing that
962 # method.
963
964 if ($y -> is_inf()) {
965 my ($quo, $rem);
966 if ($wantarray) {
967 if ($x -> is_zero() || $x -> bcmp(0) == $y -> bcmp(0)) {
968 $rem = $x -> copy();
969 $quo = $x -> bzero();
970 } else {
971 $rem = $class -> binf($y -> {sign});
972 $quo = $x -> bone('-');
973 }
974 return ($quo, $rem);
975 } else {
976 if ($y -> is_inf()) {
977 if ($x -> is_nan() || $x -> is_inf()) {
978 return $x -> bnan();
979 } else {
980 return $x -> bzero();
981 }
982 }
983 }
984 }
985
986 # At this point, both the numerator and denominator are finite numbers, and
987 # the denominator (divisor) is non-zero.
988
989 # x == 0?
990 return wantarray ? ($x, $class->bzero()) : $x if $x->is_zero();
991
992 # XXX TODO: list context, upgrade
993 # According to Knuth, this can be optimized by doing gcd twice (for d and n)
994 # and reducing in one step. This would save us the bnorm() at the end.
0c2fbbe3
CBW
995 #
996 # p r p * s (p / gcd(p, r)) * (s / gcd(s, q))
997 # - / - = ----- = ---------------------------------
998 # q s q * r (q / gcd(s, q)) * (r / gcd(p, r))
6320cdc0 999
0c2fbbe3
CBW
1000 $x->{_n} = $LIB->_mul($x->{_n}, $y->{_d});
1001 $x->{_d} = $LIB->_mul($x->{_d}, $y->{_n});
6320cdc0
SH
1002
1003 # compute new sign
1004 $x->{sign} = $x->{sign} eq $y->{sign} ? '+' : '-';
1005
1006 $x -> bnorm();
1007 if (wantarray) {
1008 my $rem = $x -> copy();
1009 $x -> bfloor();
1010 $x -> round(@r);
1011 $rem -> bsub($x -> copy()) -> bmul($y);
1012 return $x, $rem;
1013 } else {
1014 $x -> round(@r);
1015 return $x;
1016 }
1017}
1018
1019sub bmod {
1020 # compute "remainder" (in Perl way) of $x / $y
1021
1022 # set up parameters
1023 my ($class, $x, $y, @r) = (ref($_[0]), @_);
1024 # objectify is costly, so avoid it
1025 if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) {
1026 ($class, $x, $y, @r) = objectify(2, @_);
1027 }
1028
1029 return $x if $x->modify('bmod');
1030
1031 # At least one argument is NaN. This is handled the same way as in
1032 # Math::BigInt -> bmod().
1033
1034 if ($x -> is_nan() || $y -> is_nan()) {
1035 return $x -> bnan();
1036 }
1037
1038 # Modulo zero. This is handled the same way as in Math::BigInt -> bmod().
1039
1040 if ($y -> is_zero()) {
1041 return $x;
1042 }
1043
1044 # Numerator (dividend) is +/-inf. This is handled the same way as in
1045 # Math::BigInt -> bmod().
1046
1047 if ($x -> is_inf()) {
1048 return $x -> bnan();
1049 }
1050
1051 # Denominator (divisor) is +/-inf. This is handled the same way as in
1052 # Math::BigInt -> bmod().
1053
1054 if ($y -> is_inf()) {
1055 if ($x -> is_zero() || $x -> bcmp(0) == $y -> bcmp(0)) {
1056 return $x;
1057 } else {
1058 return $x -> binf($y -> sign());
1059 }
1060 }
1061
1062 # At this point, both the numerator and denominator are finite numbers, and
1063 # the denominator (divisor) is non-zero.
1064
1065 return $x if $x->is_zero(); # 0 / 7 = 0, mod 0
1066
1067 # Compute $x - $y * floor($x/$y). This can probably be optimized by working
1068 # on a lower level.
1069
1070 $x -> bsub($x -> copy() -> bdiv($y) -> bfloor() -> bmul($y));
1071 return $x -> round(@r);
1072}
1073
1074##############################################################################
1075# bdec/binc
1076
1077sub bdec {
1078 # decrement value (subtract 1)
1079 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
1080
1081 return $x if $x->{sign} !~ /^[+-]$/; # NaN, inf, -inf
1082
1083 if ($x->{sign} eq '-') {
0c2fbbe3 1084 $x->{_n} = $LIB->_add($x->{_n}, $x->{_d}); # -5/2 => -7/2
6320cdc0 1085 } else {
0c2fbbe3 1086 if ($LIB->_acmp($x->{_n}, $x->{_d}) < 0) # n < d?
6320cdc0
SH
1087 {
1088 # 1/3 -- => -2/3
0c2fbbe3 1089 $x->{_n} = $LIB->_sub($LIB->_copy($x->{_d}), $x->{_n});
6320cdc0
SH
1090 $x->{sign} = '-';
1091 } else {
0c2fbbe3 1092 $x->{_n} = $LIB->_sub($x->{_n}, $x->{_d}); # 5/2 => 3/2
6320cdc0
SH
1093 }
1094 }
1095 $x->bnorm()->round(@r);
1096}
1097
1098sub binc {
1099 # increment value (add 1)
1100 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
1101
1102 return $x if $x->{sign} !~ /^[+-]$/; # NaN, inf, -inf
1103
1104 if ($x->{sign} eq '-') {
0c2fbbe3 1105 if ($LIB->_acmp($x->{_n}, $x->{_d}) < 0) {
6320cdc0 1106 # -1/3 ++ => 2/3 (overflow at 0)
0c2fbbe3 1107 $x->{_n} = $LIB->_sub($LIB->_copy($x->{_d}), $x->{_n});
6320cdc0
SH
1108 $x->{sign} = '+';
1109 } else {
0c2fbbe3 1110 $x->{_n} = $LIB->_sub($x->{_n}, $x->{_d}); # -5/2 => -3/2
6320cdc0
SH
1111 }
1112 } else {
0c2fbbe3 1113 $x->{_n} = $LIB->_add($x->{_n}, $x->{_d}); # 5/2 => 7/2
6320cdc0
SH
1114 }
1115 $x->bnorm()->round(@r);
1116}
1117
1118##############################################################################
1119# is_foo methods (the rest is inherited)
1120
1121sub is_int {
1122 # return true if arg (BRAT or num_str) is an integer
1123 my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
1124
1125 return 1 if ($x->{sign} =~ /^[+-]$/) && # NaN and +-inf aren't
0c2fbbe3 1126 $LIB->_is_one($x->{_d}); # x/y && y != 1 => no integer
6320cdc0
SH
1127 0;
1128}
1129
1130sub is_zero {
1131 # return true if arg (BRAT or num_str) is zero
1132 my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
1133
0c2fbbe3 1134 return 1 if $x->{sign} eq '+' && $LIB->_is_zero($x->{_n});
6320cdc0
SH
1135 0;
1136}
1137
1138sub is_one {
1139 # return true if arg (BRAT or num_str) is +1 or -1 if signis given
1140 my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
1141
3cc1ad36
SH
1142 croak "too many arguments for is_one()" if @_ > 2;
1143 my $sign = $_[1] || '';
1144 $sign = '+' if $sign ne '-';
1145 return 1 if ($x->{sign} eq $sign &&
1146 $LIB->_is_one($x->{_n}) && $LIB->_is_one($x->{_d}));
6320cdc0
SH
1147 0;
1148}
1149
1150sub is_odd {
1151 # return true if arg (BFLOAT or num_str) is odd or false if even
1152 my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
1153
1154 return 1 if ($x->{sign} =~ /^[+-]$/) && # NaN & +-inf aren't
0c2fbbe3 1155 ($LIB->_is_one($x->{_d}) && $LIB->_is_odd($x->{_n})); # x/2 is not, but 3/1
6320cdc0
SH
1156 0;
1157}
1158
1159sub is_even {
1160 # return true if arg (BINT or num_str) is even or false if odd
1161 my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
1162
1163 return 0 if $x->{sign} !~ /^[+-]$/; # NaN & +-inf aren't
0c2fbbe3
CBW
1164 return 1 if ($LIB->_is_one($x->{_d}) # x/3 is never
1165 && $LIB->_is_even($x->{_n})); # but 4/1 is
6320cdc0
SH
1166 0;
1167}
1168
1169##############################################################################
1170# parts() and friends
1171
1172sub numerator {
1173 my ($class, $x) = ref($_[0]) ? (ref($_[0]), $_[0]) : objectify(1, @_);
1174
1175 # NaN, inf, -inf
1176 return Math::BigInt->new($x->{sign}) if ($x->{sign} !~ /^[+-]$/);
1177
0c2fbbe3 1178 my $n = Math::BigInt->new($LIB->_str($x->{_n}));
6320cdc0
SH
1179 $n->{sign} = $x->{sign};
1180 $n;
1181}
1182
1183sub denominator {
1184 my ($class, $x) = ref($_[0]) ? (ref($_[0]), $_[0]) : objectify(1, @_);
1185
1186 # NaN
1187 return Math::BigInt->new($x->{sign}) if $x->{sign} eq 'NaN';
1188 # inf, -inf
1189 return Math::BigInt->bone() if $x->{sign} !~ /^[+-]$/;
1190
0c2fbbe3 1191 Math::BigInt->new($LIB->_str($x->{_d}));
6320cdc0
SH
1192}
1193
1194sub parts {
1195 my ($class, $x) = ref($_[0]) ? (ref($_[0]), $_[0]) : objectify(1, @_);
1196
1197 my $c = 'Math::BigInt';
1198
1199 return ($c->bnan(), $c->bnan()) if $x->{sign} eq 'NaN';
1200 return ($c->binf(), $c->binf()) if $x->{sign} eq '+inf';
1201 return ($c->binf('-'), $c->binf()) if $x->{sign} eq '-inf';
1202
0c2fbbe3 1203 my $n = $c->new($LIB->_str($x->{_n}));
6320cdc0 1204 $n->{sign} = $x->{sign};
0c2fbbe3 1205 my $d = $c->new($LIB->_str($x->{_d}));
6320cdc0
SH
1206 ($n, $d);
1207}
1208
1209sub length {
1210 my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
1211
1212 return $nan unless $x->is_int();
0c2fbbe3 1213 $LIB->_len($x->{_n}); # length(-123/1) => length(123)
6320cdc0
SH
1214}
1215
1216sub digit {
1217 my ($class, $x, $n) = ref($_[0]) ? (undef, $_[0], $_[1]) : objectify(1, @_);
1218
1219 return $nan unless $x->is_int();
0c2fbbe3 1220 $LIB->_digit($x->{_n}, $n || 0); # digit(-123/1, 2) => digit(123, 2)
6320cdc0
SH
1221}
1222
1223##############################################################################
1224# special calc routines
1225
1226sub bceil {
1227 my ($class, $x) = ref($_[0]) ? (ref($_[0]), $_[0]) : objectify(1, @_);
1228
1229 return $x if ($x->{sign} !~ /^[+-]$/ || # not for NaN, inf
0c2fbbe3 1230 $LIB->_is_one($x->{_d})); # 22/1 => 22, 0/1 => 0
6320cdc0 1231
0c2fbbe3
CBW
1232 $x->{_n} = $LIB->_div($x->{_n}, $x->{_d}); # 22/7 => 3/1 w/ truncate
1233 $x->{_d} = $LIB->_one(); # d => 1
1234 $x->{_n} = $LIB->_inc($x->{_n}) if $x->{sign} eq '+'; # +22/7 => 4/1
1235 $x->{sign} = '+' if $x->{sign} eq '-' && $LIB->_is_zero($x->{_n}); # -0 => 0
6320cdc0
SH
1236 $x;
1237}
1238
1239sub bfloor {
1240 my ($class, $x) = ref($_[0]) ? (ref($_[0]), $_[0]) : objectify(1, @_);
1241
1242 return $x if ($x->{sign} !~ /^[+-]$/ || # not for NaN, inf
0c2fbbe3 1243 $LIB->_is_one($x->{_d})); # 22/1 => 22, 0/1 => 0
6320cdc0 1244
0c2fbbe3
CBW
1245 $x->{_n} = $LIB->_div($x->{_n}, $x->{_d}); # 22/7 => 3/1 w/ truncate
1246 $x->{_d} = $LIB->_one(); # d => 1
1247 $x->{_n} = $LIB->_inc($x->{_n}) if $x->{sign} eq '-'; # -22/7 => -4/1
6320cdc0
SH
1248 $x;
1249}
1250
1251sub bint {
7deec013 1252 my ($class, $x) = ref($_[0]) ? (ref($_[0]), $_[0]) : objectify(1, @_);
6320cdc0
SH
1253
1254 return $x if ($x->{sign} !~ /^[+-]$/ || # +/-inf or NaN
0c2fbbe3 1255 $LIB -> _is_one($x->{_d})); # already an integer
6320cdc0 1256
0c2fbbe3
CBW
1257 $x->{_n} = $LIB->_div($x->{_n}, $x->{_d}); # 22/7 => 3/1 w/ truncate
1258 $x->{_d} = $LIB->_one(); # d => 1
1259 $x->{sign} = '+' if $x->{sign} eq '-' && $LIB -> _is_zero($x->{_n});
6320cdc0
SH
1260 return $x;
1261}
1262
1263sub bfac {
1264 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
1265
1266 # if $x is not an integer
0c2fbbe3 1267 if (($x->{sign} ne '+') || (!$LIB->_is_one($x->{_d}))) {
6320cdc0
SH
1268 return $x->bnan();
1269 }
1270
0c2fbbe3 1271 $x->{_n} = $LIB->_fac($x->{_n});
6320cdc0
SH
1272 # since _d is 1, we don't need to reduce/norm the result
1273 $x->round(@r);
1274}
1275
1276sub bpow {
1277 # power ($x ** $y)
1278
1279 # set up parameters
1280 my ($class, $x, $y, @r) = (ref($_[0]), @_);
1281
1282 # objectify is costly, so avoid it
1283 if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) {
1284 ($class, $x, $y, @r) = objectify(2, @_);
1285 }
1286
3cc1ad36
SH
1287 # $x and/or $y is a NaN
1288 return $x->bnan() if $x->is_nan() || $y->is_nan();
6320cdc0 1289
3cc1ad36
SH
1290 # $x and/or $y is a +/-Inf
1291 if ($x->is_inf("-")) {
1292 return $x->bzero() if $y->is_negative();
1293 return $x->bnan() if $y->is_zero();
1294 return $x if $y->is_odd();
1295 return $x->bneg();
1296 } elsif ($x->is_inf("+")) {
1297 return $x->bzero() if $y->is_negative();
1298 return $x->bnan() if $y->is_zero();
1299 return $x;
1300 } elsif ($y->is_inf("-")) {
1301 return $x->bnan() if $x -> is_one("-");
1302 return $x->binf("+") if $x > -1 && $x < 1;
1303 return $x->bone() if $x -> is_one("+");
1304 return $x->bzero();
1305 } elsif ($y->is_inf("+")) {
1306 return $x->bnan() if $x -> is_one("-");
1307 return $x->bzero() if $x > -1 && $x < 1;
1308 return $x->bone() if $x -> is_one("+");
1309 return $x->binf("+");
1310 }
1311
1312 if ($x->is_zero()) {
1313 return $x->binf() if $y->is_negative();
1314 return $x->bone("+") if $y->is_zero();
1315 return $x;
1316 } elsif ($x->is_one()) {
1317 return $x->round(@r) if $y->is_odd(); # x is -1, y is odd => -1
1318 return $x->babs()->round(@r); # x is -1, y is even => 1
1319 } elsif ($y->is_zero()) {
1320 return $x->bone(@r); # x^0 and x != 0 => 1
1321 } elsif ($y->is_one()) {
1322 return $x->round(@r); # x^1 => x
6320cdc0 1323 }
6320cdc0 1324
3cc1ad36
SH
1325 # we don't support complex numbers, so return NaN
1326 return $x->bnan() if $x->is_negative() && !$y->is_int();
6320cdc0 1327
3cc1ad36
SH
1328 # (a/b)^-(c/d) = (b/a)^(c/d)
1329 ($x->{_n}, $x->{_d}) = ($x->{_d}, $x->{_n}) if $y->is_negative();
6320cdc0 1330
3cc1ad36
SH
1331 unless ($LIB->_is_one($y->{_n})) {
1332 $x->{_n} = $LIB->_pow($x->{_n}, $y->{_n});
0c2fbbe3 1333 $x->{_d} = $LIB->_pow($x->{_d}, $y->{_n});
0c2fbbe3 1334 $x->{sign} = '+' if $x->{sign} eq '-' && $LIB->_is_even($y->{_n});
6320cdc0
SH
1335 }
1336
3cc1ad36
SH
1337 unless ($LIB->_is_one($y->{_d})) {
1338 return $x->bsqrt(@r) if $LIB->_is_two($y->{_d}); # 1/2 => sqrt
1339 return $x->broot($LIB->_str($y->{_d}), @r); # 1/N => root(N)
1340 }
6320cdc0 1341
3cc1ad36 1342 return $x->round(@r);
6320cdc0
SH
1343}
1344
1345sub blog {
1346 # Return the logarithm of the operand. If a second operand is defined, that
1347 # value is used as the base, otherwise the base is assumed to be Euler's
1348 # constant.
1349
92c15a49
EH
1350 my ($class, $x, $base, @r);
1351
6320cdc0
SH
1352 # Don't objectify the base, since an undefined base, as in $x->blog() or
1353 # $x->blog(undef) signals that the base is Euler's number.
1354
92c15a49
EH
1355 if (!ref($_[0]) && $_[0] =~ /^[A-Za-z]|::/) {
1356 # E.g., Math::BigFloat->blog(256, 2)
1357 ($class, $x, $base, @r) =
1358 defined $_[2] ? objectify(2, @_) : objectify(1, @_);
1359 } else {
1360 # E.g., Math::BigFloat::blog(256, 2) or $x->blog(2)
1361 ($class, $x, $base, @r) =
1362 defined $_[1] ? objectify(2, @_) : objectify(1, @_);
6320cdc0
SH
1363 }
1364
1365 return $x if $x->modify('blog');
1366
1367 # Handle all exception cases and all trivial cases. I have used Wolfram Alpha
1368 # (http://www.wolframalpha.com) as the reference for these cases.
1369
1370 return $x -> bnan() if $x -> is_nan();
1371
1372 if (defined $base) {
1373 $base = $class -> new($base) unless ref $base;
1374 if ($base -> is_nan() || $base -> is_one()) {
1375 return $x -> bnan();
1376 } elsif ($base -> is_inf() || $base -> is_zero()) {
1377 return $x -> bnan() if $x -> is_inf() || $x -> is_zero();
1378 return $x -> bzero();
1379 } elsif ($base -> is_negative()) { # -inf < base < 0
1380 return $x -> bzero() if $x -> is_one(); # x = 1
1381 return $x -> bone() if $x == $base; # x = base
1382 return $x -> bnan(); # otherwise
1383 }
1384 return $x -> bone() if $x == $base; # 0 < base && 0 < x < inf
1385 }
1386
1387 # We now know that the base is either undefined or positive and finite.
1388
1389 if ($x -> is_inf()) { # x = +/-inf
1390 my $sign = defined $base && $base < 1 ? '-' : '+';
1391 return $x -> binf($sign);
1392 } elsif ($x -> is_neg()) { # -inf < x < 0
1393 return $x -> bnan();
1394 } elsif ($x -> is_one()) { # x = 1
1395 return $x -> bzero();
1396 } elsif ($x -> is_zero()) { # x = 0
1397 my $sign = defined $base && $base < 1 ? '+' : '-';
1398 return $x -> binf($sign);
1399 }
1400
1401 # At this point we are done handling all exception cases and trivial cases.
1402
1403 $base = Math::BigFloat -> new($base) if defined $base;
1404
0c2fbbe3
CBW
1405 my $xn = Math::BigFloat -> new($LIB -> _str($x->{_n}));
1406 my $xd = Math::BigFloat -> new($LIB -> _str($x->{_d}));
6320cdc0
SH
1407
1408 my $xtmp = Math::BigRat -> new($xn -> bdiv($xd) -> blog($base, @r) -> bsstr());
1409
1410 $x -> {sign} = $xtmp -> {sign};
1411 $x -> {_n} = $xtmp -> {_n};
1412 $x -> {_d} = $xtmp -> {_d};
1413
1414 return $x;
1415}
1416
1417sub bexp {
1418 # set up parameters
1419 my ($class, $x, $y, @r) = (ref($_[0]), @_);
1420
1421 # objectify is costly, so avoid it
1422 if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) {
92c15a49 1423 ($class, $x, $y, @r) = objectify(1, @_);
6320cdc0
SH
1424 }
1425
1426 return $x->binf(@r) if $x->{sign} eq '+inf';
1427 return $x->bzero(@r) if $x->{sign} eq '-inf';
1428
1429 # we need to limit the accuracy to protect against overflow
1430 my $fallback = 0;
1431 my ($scale, @params);
1432 ($x, @params) = $x->_find_round_parameters(@r);
1433
1434 # also takes care of the "error in _find_round_parameters?" case
1435 return $x if $x->{sign} eq 'NaN';
1436
1437 # no rounding at all, so must use fallback
1438 if (scalar @params == 0) {
1439 # simulate old behaviour
1440 $params[0] = $class->div_scale(); # and round to it as accuracy
1441 $params[1] = undef; # P = undef
1442 $scale = $params[0]+4; # at least four more for proper round
1443 $params[2] = $r[2]; # round mode by caller or undef
1444 $fallback = 1; # to clear a/p afterwards
1445 } else {
1446 # the 4 below is empirical, and there might be cases where it's not enough...
1447 $scale = abs($params[0] || $params[1]) + 4; # take whatever is defined
1448 }
1449
1450 return $x->bone(@params) if $x->is_zero();
1451
1452 # See the comments in Math::BigFloat on how this algorithm works.
1453 # Basically we calculate A and B (where B is faculty(N)) so that A/B = e
1454
1455 my $x_org = $x->copy();
1456 if ($scale <= 75) {
1457 # set $x directly from a cached string form
1458 $x->{_n} =
0c2fbbe3 1459 $LIB->_new("90933395208605785401971970164779391644753259799242");
6320cdc0 1460 $x->{_d} =
0c2fbbe3 1461 $LIB->_new("33452526613163807108170062053440751665152000000000");
6320cdc0
SH
1462 $x->{sign} = '+';
1463 } else {
1464 # compute A and B so that e = A / B.
1465
1466 # After some terms we end up with this, so we use it as a starting point:
0c2fbbe3
CBW
1467 my $A = $LIB->_new("90933395208605785401971970164779391644753259799242");
1468 my $F = $LIB->_new(42); my $step = 42;
6320cdc0
SH
1469
1470 # Compute how many steps we need to take to get $A and $B sufficiently big
1471 my $steps = Math::BigFloat::_len_to_steps($scale - 4);
1472 # print STDERR "# Doing $steps steps for ", $scale-4, " digits\n";
1473 while ($step++ <= $steps) {
1474 # calculate $a * $f + 1
0c2fbbe3
CBW
1475 $A = $LIB->_mul($A, $F);
1476 $A = $LIB->_inc($A);
6320cdc0 1477 # increment f
0c2fbbe3 1478 $F = $LIB->_inc($F);
6320cdc0
SH
1479 }
1480 # compute $B as factorial of $steps (this is faster than doing it manually)
0c2fbbe3 1481 my $B = $LIB->_fac($LIB->_new($steps));
6320cdc0 1482
0c2fbbe3 1483 # print "A ", $LIB->_str($A), "\nB ", $LIB->_str($B), "\n";
6320cdc0
SH
1484
1485 $x->{_n} = $A;
1486 $x->{_d} = $B;
1487 $x->{sign} = '+';
3f185657
PJA
1488 }
1489
6320cdc0
SH
1490 # $x contains now an estimate of e, with some surplus digits, so we can round
1491 if (!$x_org->is_one()) {
1492 # raise $x to the wanted power and round it in one step:
1493 $x->bpow($x_org, @params);
1494 } else {
1495 # else just round the already computed result
1496 delete $x->{_a}; delete $x->{_p};
1497 # shortcut to not run through _find_round_parameters again
1498 if (defined $params[0]) {
1499 $x->bround($params[0], $params[2]); # then round accordingly
1500 } else {
1501 $x->bfround($params[1], $params[2]); # then round accordingly
1502 }
1503 }
1504 if ($fallback) {
1505 # clear a/p after round, since user did not request it
1506 delete $x->{_a}; delete $x->{_p};
990fb837
RGS
1507 }
1508
6320cdc0
SH
1509 $x;
1510}
990fb837 1511
6320cdc0
SH
1512sub bnok {
1513 # set up parameters
1514 my ($class, $x, $y, @r) = (ref($_[0]), @_);
990fb837 1515
6320cdc0
SH
1516 # objectify is costly, so avoid it
1517 if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) {
1518 ($class, $x, $y, @r) = objectify(2, @_);
3f185657 1519 }
990fb837 1520
7deec013
NB
1521 return $x->bnan() if $x->is_nan() || $y->is_nan();
1522 return $x->bnan() if (($x->is_finite() && !$x->is_int()) ||
1523 ($y->is_finite() && !$y->is_int()));
1524
1525 my $xint = Math::BigInt -> new($x -> bstr());
1526 my $yint = Math::BigInt -> new($y -> bstr());
6320cdc0 1527 $xint -> bnok($yint);
7deec013 1528 my $xrat = Math::BigRat -> new($xint);
ccbfef19 1529
7deec013
NB
1530 $x -> {sign} = $xrat -> {sign};
1531 $x -> {_n} = $xrat -> {_n};
1532 $x -> {_d} = $xrat -> {_d};
ccbfef19 1533
6320cdc0
SH
1534 return $x;
1535}
990fb837 1536
6320cdc0
SH
1537sub broot {
1538 # set up parameters
1539 my ($class, $x, $y, @r) = (ref($_[0]), @_);
1540 # objectify is costly, so avoid it
1541 if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) {
1542 ($class, $x, $y, @r) = objectify(2, @_);
3f185657 1543 }
990fb837 1544
6320cdc0 1545 # Convert $x into a Math::BigFloat.
3f185657 1546
0c2fbbe3
CBW
1547 my $xd = Math::BigFloat -> new($LIB -> _str($x->{_d}));
1548 my $xflt = Math::BigFloat -> new($LIB -> _str($x->{_n})) -> bdiv($xd);
6320cdc0 1549 $xflt -> {sign} = $x -> {sign};
3f185657 1550
6320cdc0 1551 # Convert $y into a Math::BigFloat.
3f185657 1552
0c2fbbe3
CBW
1553 my $yd = Math::BigFloat -> new($LIB -> _str($y->{_d}));
1554 my $yflt = Math::BigFloat -> new($LIB -> _str($y->{_n})) -> bdiv($yd);
6320cdc0 1555 $yflt -> {sign} = $y -> {sign};
3f185657 1556
6320cdc0 1557 # Compute the root and convert back to a Math::BigRat.
990fb837 1558
6320cdc0
SH
1559 $xflt -> broot($yflt, @r);
1560 my $xtmp = Math::BigRat -> new($xflt -> bsstr());
a4e2b1c6 1561
6320cdc0
SH
1562 $x -> {sign} = $xtmp -> {sign};
1563 $x -> {_n} = $xtmp -> {_n};
1564 $x -> {_d} = $xtmp -> {_d};
a4e2b1c6 1565
6320cdc0
SH
1566 return $x;
1567}
a4e2b1c6 1568
6320cdc0
SH
1569sub bmodpow {
1570 # set up parameters
1571 my ($class, $x, $y, $m, @r) = (ref($_[0]), @_);
1572 # objectify is costly, so avoid it
1573 if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) {
1574 ($class, $x, $y, $m, @r) = objectify(3, @_);
a4e2b1c6 1575 }
a4e2b1c6 1576
6320cdc0 1577 # Convert $x, $y, and $m into Math::BigInt objects.
ccbfef19 1578
6320cdc0
SH
1579 my $xint = Math::BigInt -> new($x -> copy() -> bint());
1580 my $yint = Math::BigInt -> new($y -> copy() -> bint());
1581 my $mint = Math::BigInt -> new($m -> copy() -> bint());
a4e2b1c6 1582
7deec013 1583 $xint -> bmodpow($yint, $mint, @r);
6320cdc0 1584 my $xtmp = Math::BigRat -> new($xint -> bsstr());
a4e2b1c6 1585
6320cdc0
SH
1586 $x -> {sign} = $xtmp -> {sign};
1587 $x -> {_n} = $xtmp -> {_n};
1588 $x -> {_d} = $xtmp -> {_d};
1589 return $x;
1590}
184f15d5 1591
6320cdc0
SH
1592sub bmodinv {
1593 # set up parameters
1594 my ($class, $x, $y, @r) = (ref($_[0]), @_);
1595 # objectify is costly, so avoid it
1596 if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) {
1597 ($class, $x, $y, @r) = objectify(2, @_);
1598 }
184f15d5 1599
6320cdc0 1600 # Convert $x and $y into Math::BigInt objects.
184f15d5 1601
6320cdc0
SH
1602 my $xint = Math::BigInt -> new($x -> copy() -> bint());
1603 my $yint = Math::BigInt -> new($y -> copy() -> bint());
a4e2b1c6 1604
7deec013 1605 $xint -> bmodinv($yint, @r);
6320cdc0 1606 my $xtmp = Math::BigRat -> new($xint -> bsstr());
a4e2b1c6 1607
6320cdc0
SH
1608 $x -> {sign} = $xtmp -> {sign};
1609 $x -> {_n} = $xtmp -> {_n};
1610 $x -> {_d} = $xtmp -> {_d};
1611 return $x;
1612}
184f15d5 1613
6320cdc0
SH
1614sub bsqrt {
1615 my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
184f15d5 1616
6320cdc0
SH
1617 return $x->bnan() if $x->{sign} !~ /^[+]/; # NaN, -inf or < 0
1618 return $x if $x->{sign} eq '+inf'; # sqrt(inf) == inf
1619 return $x->round(@r) if $x->is_zero() || $x->is_one();
ccbfef19 1620
3cc1ad36
SH
1621 my $n = $x -> {_n};
1622 my $d = $x -> {_d};
1623
1624 # Look for an exact solution. For the numerator and the denominator, take
1625 # the square root and square it and see if we got the original value. If we
1626 # did, for both the numerator and the denominator, we have an exact
1627 # solution.
1628
1629 {
1630 my $nsqrt = $LIB -> _sqrt($LIB -> _copy($n));
1631 my $n2 = $LIB -> _mul($LIB -> _copy($nsqrt), $nsqrt);
1632 if ($LIB -> _acmp($n, $n2) == 0) {
1633 my $dsqrt = $LIB -> _sqrt($LIB -> _copy($d));
1634 my $d2 = $LIB -> _mul($LIB -> _copy($dsqrt), $dsqrt);
1635 if ($LIB -> _acmp($d, $d2) == 0) {
1636 $x -> {_n} = $nsqrt;
1637 $x -> {_d} = $dsqrt;
1638 return $x->round(@r);
1639 }
1640 }
1641 }
1642
1643 local $Math::BigFloat::upgrade = undef;
6320cdc0
SH
1644 local $Math::BigFloat::downgrade = undef;
1645 local $Math::BigFloat::precision = undef;
3cc1ad36
SH
1646 local $Math::BigFloat::accuracy = undef;
1647 local $Math::BigInt::upgrade = undef;
1648 local $Math::BigInt::precision = undef;
1649 local $Math::BigInt::accuracy = undef;
184f15d5 1650
3cc1ad36
SH
1651 my $xn = Math::BigFloat -> new($LIB -> _str($n));
1652 my $xd = Math::BigFloat -> new($LIB -> _str($d));
184f15d5 1653
6320cdc0 1654 my $xtmp = Math::BigRat -> new($xn -> bdiv($xd) -> bsqrt() -> bsstr());
12fc2493 1655
6320cdc0
SH
1656 $x -> {sign} = $xtmp -> {sign};
1657 $x -> {_n} = $xtmp -> {_n};
1658 $x -> {_d} = $xtmp -> {_d};
a4e2b1c6 1659
6320cdc0
SH
1660 $x->round(@r);
1661}
184f15d5 1662
6320cdc0 1663sub blsft {
7deec013 1664 my ($class, $x, $y, $b) = objectify(2, @_);
9b924220 1665
6320cdc0
SH
1666 $b = 2 if !defined $b;
1667 $b = $class -> new($b) unless ref($b) && $b -> isa($class);
184f15d5 1668
6320cdc0 1669 return $x -> bnan() if $x -> is_nan() || $y -> is_nan() || $b -> is_nan();
9b924220 1670
6320cdc0
SH
1671 # shift by a negative amount?
1672 return $x -> brsft($y -> copy() -> babs(), $b) if $y -> {sign} =~ /^-/;
184f15d5 1673
6320cdc0
SH
1674 $x -> bmul($b -> bpow($y));
1675}
184f15d5 1676
6320cdc0 1677sub brsft {
7deec013 1678 my ($class, $x, $y, $b) = objectify(2, @_);
12fc2493 1679
6320cdc0
SH
1680 $b = 2 if !defined $b;
1681 $b = $class -> new($b) unless ref($b) && $b -> isa($class);
184f15d5 1682
6320cdc0 1683 return $x -> bnan() if $x -> is_nan() || $y -> is_nan() || $b -> is_nan();
7d341013 1684
6320cdc0
SH
1685 # shift by a negative amount?
1686 return $x -> blsft($y -> copy() -> babs(), $b) if $y -> {sign} =~ /^-/;
184f15d5 1687
6320cdc0
SH
1688 # the following call to bdiv() will return either quotient (scalar context)
1689 # or quotient and remainder (list context).
1690 $x -> bdiv($b -> bpow($y));
1691}
12fc2493 1692
6320cdc0
SH
1693sub band {
1694 my $x = shift;
1695 my $xref = ref($x);
1696 my $class = $xref || $x;
12fc2493 1697
3cc1ad36
SH
1698 croak 'band() is an instance method, not a class method' unless $xref;
1699 croak 'Not enough arguments for band()' if @_ < 1;
184f15d5 1700
6320cdc0
SH
1701 my $y = shift;
1702 $y = $class -> new($y) unless ref($y);
4de3d162 1703
6320cdc0 1704 my @r = @_;
a4e2b1c6 1705
6320cdc0
SH
1706 my $xtmp = Math::BigInt -> new($x -> bint()); # to Math::BigInt
1707 $xtmp -> band($y);
1708 $xtmp = $class -> new($xtmp); # back to Math::BigRat
12fc2493 1709
6320cdc0
SH
1710 $x -> {sign} = $xtmp -> {sign};
1711 $x -> {_n} = $xtmp -> {_n};
1712 $x -> {_d} = $xtmp -> {_d};
4de3d162 1713
6320cdc0
SH
1714 return $x -> round(@r);
1715}
4de3d162 1716
6320cdc0
SH
1717sub bior {
1718 my $x = shift;
1719 my $xref = ref($x);
1720 my $class = $xref || $x;
4de3d162 1721
3cc1ad36
SH
1722 croak 'bior() is an instance method, not a class method' unless $xref;
1723 croak 'Not enough arguments for bior()' if @_ < 1;
184f15d5 1724
6320cdc0
SH
1725 my $y = shift;
1726 $y = $class -> new($y) unless ref($y);
11c955be 1727
6320cdc0 1728 my @r = @_;
11c955be 1729
6320cdc0
SH
1730 my $xtmp = Math::BigInt -> new($x -> bint()); # to Math::BigInt
1731 $xtmp -> bior($y);
1732 $xtmp = $class -> new($xtmp); # back to Math::BigRat
7afd7a91 1733
6320cdc0
SH
1734 $x -> {sign} = $xtmp -> {sign};
1735 $x -> {_n} = $xtmp -> {_n};
1736 $x -> {_d} = $xtmp -> {_d};
7afd7a91 1737
6320cdc0
SH
1738 return $x -> round(@r);
1739}
116a1b2f 1740
6320cdc0
SH
1741sub bxor {
1742 my $x = shift;
1743 my $xref = ref($x);
1744 my $class = $xref || $x;
116a1b2f 1745
3cc1ad36
SH
1746 croak 'bxor() is an instance method, not a class method' unless $xref;
1747 croak 'Not enough arguments for bxor()' if @_ < 1;
116a1b2f 1748
6320cdc0
SH
1749 my $y = shift;
1750 $y = $class -> new($y) unless ref($y);
116a1b2f 1751
6320cdc0 1752 my @r = @_;
116a1b2f 1753
6320cdc0
SH
1754 my $xtmp = Math::BigInt -> new($x -> bint()); # to Math::BigInt
1755 $xtmp -> bxor($y);
1756 $xtmp = $class -> new($xtmp); # back to Math::BigRat
116a1b2f 1757
6320cdc0
SH
1758 $x -> {sign} = $xtmp -> {sign};
1759 $x -> {_n} = $xtmp -> {_n};
1760 $x -> {_d} = $xtmp -> {_d};
116a1b2f 1761
6320cdc0
SH
1762 return $x -> round(@r);
1763}
116a1b2f 1764
6320cdc0
SH
1765sub bnot {
1766 my $x = shift;
1767 my $xref = ref($x);
1768 my $class = $xref || $x;
116a1b2f 1769
3cc1ad36 1770 croak 'bnot() is an instance method, not a class method' unless $xref;
116a1b2f 1771
6320cdc0 1772 my @r = @_;
116a1b2f 1773
6320cdc0
SH
1774 my $xtmp = Math::BigInt -> new($x -> bint()); # to Math::BigInt
1775 $xtmp -> bnot();
1776 $xtmp = $class -> new($xtmp); # back to Math::BigRat
116a1b2f 1777
6320cdc0
SH
1778 $x -> {sign} = $xtmp -> {sign};
1779 $x -> {_n} = $xtmp -> {_n};
1780 $x -> {_d} = $xtmp -> {_d};
116a1b2f 1781
6320cdc0
SH
1782 return $x -> round(@r);
1783}
12fc2493 1784
6320cdc0
SH
1785##############################################################################
1786# round
12fc2493 1787
6320cdc0
SH
1788sub round {
1789 $_[0];
1790}
12fc2493 1791
6320cdc0
SH
1792sub bround {
1793 $_[0];
1794}
9b924220 1795
6320cdc0
SH
1796sub bfround {
1797 $_[0];
1798}
12fc2493 1799
6320cdc0
SH
1800##############################################################################
1801# comparing
7afd7a91 1802
6320cdc0
SH
1803sub bcmp {
1804 # compare two signed numbers
9b924220 1805
6320cdc0
SH
1806 # set up parameters
1807 my ($class, $x, $y) = (ref($_[0]), @_);
7afd7a91 1808
6320cdc0
SH
1809 # objectify is costly, so avoid it
1810 if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) {
1811 ($class, $x, $y) = objectify(2, @_);
7afd7a91
T
1812 }
1813
6320cdc0
SH
1814 if ($x->{sign} !~ /^[+-]$/ || $y->{sign} !~ /^[+-]$/) {
1815 # $x is NaN and/or $y is NaN
1816 return undef if $x->{sign} eq $nan || $y->{sign} eq $nan;
1817 # $x and $y are both either +inf or -inf
1818 return 0 if $x->{sign} eq $y->{sign} && $x->{sign} =~ /^[+-]inf$/;
1819 # $x = +inf and $y < +inf
1820 return +1 if $x->{sign} eq '+inf';
1821 # $x = -inf and $y > -inf
1822 return -1 if $x->{sign} eq '-inf';
1823 # $x < +inf and $y = +inf
1824 return -1 if $y->{sign} eq '+inf';
1825 # $x > -inf and $y = -inf
1826 return +1;
7afd7a91
T
1827 }
1828
6320cdc0
SH
1829 # $x >= 0 and $y < 0
1830 return 1 if $x->{sign} eq '+' && $y->{sign} eq '-';
1831 # $x < 0 and $y >= 0
1832 return -1 if $x->{sign} eq '-' && $y->{sign} eq '+';
7afd7a91 1833
6320cdc0 1834 # At this point, we know that $x and $y have the same sign.
7afd7a91 1835
6320cdc0 1836 # shortcut
0c2fbbe3
CBW
1837 my $xz = $LIB->_is_zero($x->{_n});
1838 my $yz = $LIB->_is_zero($y->{_n});
6320cdc0
SH
1839 return 0 if $xz && $yz; # 0 <=> 0
1840 return -1 if $xz && $y->{sign} eq '+'; # 0 <=> +y
1841 return 1 if $yz && $x->{sign} eq '+'; # +x <=> 0
7afd7a91 1842
0c2fbbe3
CBW
1843 my $t = $LIB->_mul($LIB->_copy($x->{_n}), $y->{_d});
1844 my $u = $LIB->_mul($LIB->_copy($y->{_n}), $x->{_d});
7afd7a91 1845
0c2fbbe3 1846 my $cmp = $LIB->_acmp($t, $u); # signs are equal
6320cdc0
SH
1847 $cmp = -$cmp if $x->{sign} eq '-'; # both are '-' => reverse
1848 $cmp;
1849}
184f15d5 1850
6320cdc0
SH
1851sub bacmp {
1852 # compare two numbers (as unsigned)
990fb837 1853
6320cdc0
SH
1854 # set up parameters
1855 my ($class, $x, $y) = (ref($_[0]), @_);
1856 # objectify is costly, so avoid it
1857 if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) {
1858 ($class, $x, $y) = objectify(2, @_);
1859 }
990fb837 1860
6320cdc0
SH
1861 if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/)) {
1862 # handle +-inf and NaN
1863 return undef if (($x->{sign} eq $nan) || ($y->{sign} eq $nan));
1864 return 0 if $x->{sign} =~ /^[+-]inf$/ && $y->{sign} =~ /^[+-]inf$/;
1865 return 1 if $x->{sign} =~ /^[+-]inf$/ && $y->{sign} !~ /^[+-]inf$/;
1866 return -1;
1867 }
9b924220 1868
0c2fbbe3
CBW
1869 my $t = $LIB->_mul($LIB->_copy($x->{_n}), $y->{_d});
1870 my $u = $LIB->_mul($LIB->_copy($y->{_n}), $x->{_d});
1871 $LIB->_acmp($t, $u); # ignore signs
6320cdc0 1872}
12fc2493 1873
6320cdc0
SH
1874sub beq {
1875 my $self = shift;
1876 my $selfref = ref $self;
7deec013 1877 #my $class = $selfref || $self;
184f15d5 1878
3cc1ad36
SH
1879 croak 'beq() is an instance method, not a class method' unless $selfref;
1880 croak 'Wrong number of arguments for beq()' unless @_ == 1;
12fc2493 1881
6320cdc0
SH
1882 my $cmp = $self -> bcmp(shift);
1883 return defined($cmp) && ! $cmp;
1884}
12fc2493 1885
6320cdc0
SH
1886sub bne {
1887 my $self = shift;
1888 my $selfref = ref $self;
7deec013 1889 #my $class = $selfref || $self;
184f15d5 1890
3cc1ad36
SH
1891 croak 'bne() is an instance method, not a class method' unless $selfref;
1892 croak 'Wrong number of arguments for bne()' unless @_ == 1;
ccbfef19 1893
6320cdc0
SH
1894 my $cmp = $self -> bcmp(shift);
1895 return defined($cmp) && ! $cmp ? '' : 1;
1896}
184f15d5 1897
6320cdc0
SH
1898sub blt {
1899 my $self = shift;
1900 my $selfref = ref $self;
7deec013 1901 #my $class = $selfref || $self;
184f15d5 1902
3cc1ad36
SH
1903 croak 'blt() is an instance method, not a class method' unless $selfref;
1904 croak 'Wrong number of arguments for blt()' unless @_ == 1;
184f15d5 1905
6320cdc0
SH
1906 my $cmp = $self -> bcmp(shift);
1907 return defined($cmp) && $cmp < 0;
1908}
184f15d5 1909
6320cdc0
SH
1910sub ble {
1911 my $self = shift;
1912 my $selfref = ref $self;
7deec013 1913 #my $class = $selfref || $self;
184f15d5 1914
3cc1ad36
SH
1915 croak 'ble() is an instance method, not a class method' unless $selfref;
1916 croak 'Wrong number of arguments for ble()' unless @_ == 1;
184f15d5 1917
6320cdc0
SH
1918 my $cmp = $self -> bcmp(shift);
1919 return defined($cmp) && $cmp <= 0;
1920}
184f15d5 1921
6320cdc0
SH
1922sub bgt {
1923 my $self = shift;
1924 my $selfref = ref $self;
7deec013 1925 #my $class = $selfref || $self;
184f15d5 1926
3cc1ad36
SH
1927 croak 'bgt() is an instance method, not a class method' unless $selfref;
1928 croak 'Wrong number of arguments for bgt()' unless @_ == 1;
ccbfef19 1929
6320cdc0
SH
1930 my $cmp = $self -> bcmp(shift);
1931 return defined($cmp) && $cmp > 0;
1932}
184f15d5 1933
6320cdc0
SH
1934sub bge {
1935 my $self = shift;
1936 my $selfref = ref $self;
7deec013 1937 #my $class = $selfref || $self;
184f15d5 1938
3cc1ad36 1939 croak 'bge() is an instance method, not a class method'
6320cdc0 1940 unless $selfref;
3cc1ad36 1941 croak 'Wrong number of arguments for bge()' unless @_ == 1;
184f15d5 1942
6320cdc0
SH
1943 my $cmp = $self -> bcmp(shift);
1944 return defined($cmp) && $cmp >= 0;
1945}
184f15d5
JH
1946
1947##############################################################################
6320cdc0 1948# output conversion
184f15d5 1949
6320cdc0
SH
1950sub numify {
1951 # convert 17/8 => float (aka 2.125)
1952 my ($self, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
ccbfef19 1953
6320cdc0 1954 # Non-finite number.
7d341013 1955
6320cdc0 1956 return $x->bstr() if $x->{sign} !~ /^[+-]$/;
93c87d9d 1957
6320cdc0 1958 # Finite number.
7d341013 1959
0c2fbbe3
CBW
1960 my $abs = $LIB->_is_one($x->{_d})
1961 ? $LIB->_num($x->{_n})
1962 : Math::BigFloat -> new($LIB->_str($x->{_n}))
1963 -> bdiv($LIB->_str($x->{_d}))
6320cdc0
SH
1964 -> bstr();
1965 return $x->{sign} eq '-' ? 0 - $abs : 0 + $abs;
1966}
1967
3cc1ad36 1968sub as_int {
6320cdc0 1969 my ($self, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
184f15d5 1970
6320cdc0
SH
1971 # NaN, inf etc
1972 return Math::BigInt->new($x->{sign}) if $x->{sign} !~ /^[+-]$/;
1973
1974 my $u = Math::BigInt->bzero();
0c2fbbe3 1975 $u->{value} = $LIB->_div($LIB->_copy($x->{_n}), $x->{_d}); # 22/7 => 3
6320cdc0
SH
1976 $u->bneg if $x->{sign} eq '-'; # no negative zero
1977 $u;
1978}
ccbfef19 1979
6320cdc0
SH
1980sub as_float {
1981 # return N/D as Math::BigFloat
184f15d5 1982
6320cdc0
SH
1983 # set up parameters
1984 my ($class, $x, @r) = (ref($_[0]), @_);
1985 # objectify is costly, so avoid it
1986 ($class, $x, @r) = objectify(1, @_) unless ref $_[0];
4de3d162 1987
6320cdc0
SH
1988 # NaN, inf etc
1989 return Math::BigFloat->new($x->{sign}) if $x->{sign} !~ /^[+-]$/;
4de3d162 1990
0c2fbbe3
CBW
1991 my $xd = Math::BigFloat -> new($LIB -> _str($x->{_d}));
1992 my $xflt = Math::BigFloat -> new($LIB -> _str($x->{_n}));
6320cdc0
SH
1993 $xflt -> {sign} = $x -> {sign};
1994 $xflt -> bdiv($xd, @r);
ccbfef19 1995
6320cdc0
SH
1996 return $xflt;
1997}
4de3d162 1998
6320cdc0
SH
1999sub as_bin {
2000 my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
9b924220 2001
6320cdc0 2002 return $x unless $x->is_int();
9b924220 2003
6320cdc0
SH
2004 my $s = $x->{sign};
2005 $s = '' if $s eq '+';
0c2fbbe3 2006 $s . $LIB->_as_bin($x->{_n});
6320cdc0 2007}
9b924220 2008
6320cdc0
SH
2009sub as_hex {
2010 my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
9b924220 2011
6320cdc0 2012 return $x unless $x->is_int();
9b924220 2013
6320cdc0 2014 my $s = $x->{sign}; $s = '' if $s eq '+';
0c2fbbe3 2015 $s . $LIB->_as_hex($x->{_n});
6320cdc0 2016}
9b924220 2017
6320cdc0
SH
2018sub as_oct {
2019 my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
b8884ce4 2020
6320cdc0 2021 return $x unless $x->is_int();
b8884ce4 2022
6320cdc0 2023 my $s = $x->{sign}; $s = '' if $s eq '+';
0c2fbbe3 2024 $s . $LIB->_as_oct($x->{_n});
6320cdc0 2025}
b8884ce4
T
2026
2027##############################################################################
2028
6320cdc0
SH
2029sub from_hex {
2030 my $class = shift;
b8884ce4 2031
6320cdc0
SH
2032 $class->new(@_);
2033}
b8884ce4 2034
6320cdc0
SH
2035sub from_bin {
2036 my $class = shift;
b8884ce4 2037
6320cdc0
SH
2038 $class->new(@_);
2039}
b8884ce4 2040
6320cdc0
SH
2041sub from_oct {
2042 my $class = shift;
b8884ce4 2043
6320cdc0
SH
2044 my @parts;
2045 for my $c (@_) {
2046 push @parts, Math::BigInt->from_oct($c);
b8884ce4 2047 }
6320cdc0
SH
2048 $class->new (@parts);
2049}
b8884ce4 2050
b68b7ab1
T
2051##############################################################################
2052# import
2053
6320cdc0
SH
2054sub import {
2055 my $class = shift;
7deec013
NB
2056 my @a;
2057 my $lib = '';
6320cdc0 2058 my $try = 'try';
9b924220 2059
7deec013
NB
2060 for (my $i = 0; $i <= $#_ ; $i++) {
2061 croak "Error in import(): argument with index $i is undefined"
2062 unless defined($_[$i]);
2063
6320cdc0
SH
2064 if ($_[$i] eq ':constant') {
2065 # this rest causes overlord er load to step in
2066 overload::constant float => sub { $class->new(shift); };
2067 }
7deec013
NB
2068
2069 #elsif ($_[$i] eq 'upgrade') {
2070 # # this causes upgrading
2071 # $upgrade = $_[$i+1]; # or undef to disable
2072 # $i++;
2073 #}
2074
6320cdc0
SH
2075 elsif ($_[$i] eq 'downgrade') {
2076 # this causes downgrading
7deec013 2077 $downgrade = $_[$i+1]; # or undef to disable
6320cdc0 2078 $i++;
7deec013
NB
2079 }
2080
2081 elsif ($_[$i] =~ /^(lib|try|only)\z/) {
2082 $lib = $_[$i+1] || '';
2083 $try = $1; # "lib", "try" or "only"
6320cdc0 2084 $i++;
7deec013
NB
2085 }
2086
2087 elsif ($_[$i] eq 'with') {
6320cdc0 2088 # this argument is no longer used
7deec013
NB
2089 # $LIB = $_[$i+1] || 'Calc';
2090 # carp "'with' is no longer supported, use 'lib', 'try', or 'only'";
6320cdc0 2091 $i++;
6320cdc0 2092 }
6de7f0cc 2093
7deec013
NB
2094 else {
2095 push @a, $_[$i];
6320cdc0 2096 }
93c87d9d 2097 }
233f7bc0 2098
7deec013 2099 require Math::BigInt;
6de7f0cc 2100
7deec013
NB
2101 my @import = ('objectify');
2102 push @import, $try, $lib if $lib ne '';
2103 Math::BigInt -> import(@import);
b68b7ab1 2104
7deec013
NB
2105 # find out which one was actually loaded
2106 $LIB = Math::BigInt -> config("lib");
ccbfef19 2107
3cc1ad36
SH
2108 # any non :constant stuff is handled by Exporter (loaded by parent class)
2109 # even if @_ is empty, to give it a chance
6320cdc0
SH
2110 $class->SUPER::import(@a); # for subclasses
2111 $class->export_to_level(1, $class, @a); # need this, too
2112}
184f15d5
JH
2113
21141;
2115
2116__END__
2117
a7752796
PJA
2118=pod
2119
184f15d5
JH
2120=head1 NAME
2121
b68b7ab1 2122Math::BigRat - Arbitrary big rational numbers
184f15d5
JH
2123
2124=head1 SYNOPSIS
2125
6320cdc0 2126 use Math::BigRat;
184f15d5 2127
6320cdc0 2128 my $x = Math::BigRat->new('3/7'); $x += '5/9';
184f15d5 2129
6320cdc0
SH
2130 print $x->bstr(), "\n";
2131 print $x ** 2, "\n";
184f15d5 2132
6320cdc0
SH
2133 my $y = Math::BigRat->new('inf');
2134 print "$y ", ($y->is_inf ? 'is' : 'is not'), " infinity\n";
7afd7a91 2135
6320cdc0 2136 my $z = Math::BigRat->new(144); $z->bsqrt();
7afd7a91 2137
184f15d5
JH
2138=head1 DESCRIPTION
2139
7d341013 2140Math::BigRat complements Math::BigInt and Math::BigFloat by providing support
b68b7ab1 2141for arbitrary big rational numbers.
184f15d5
JH
2142
2143=head2 MATH LIBRARY
2144
b8884ce4
T
2145You can change the underlying module that does the low-level
2146math operations by using:
184f15d5 2147
6320cdc0 2148 use Math::BigRat try => 'GMP';
184f15d5 2149
b8884ce4 2150Note: This needs Math::BigInt::GMP installed.
184f15d5
JH
2151
2152The following would first try to find Math::BigInt::Foo, then
2153Math::BigInt::Bar, and when this also fails, revert to Math::BigInt::Calc:
2154
6320cdc0 2155 use Math::BigRat try => 'Foo,Math::BigInt::Bar';
184f15d5 2156
6320cdc0 2157If you want to get warned when the fallback occurs, replace "try" with "lib":
184f15d5 2158
6320cdc0 2159 use Math::BigRat lib => 'Foo,Math::BigInt::Bar';
7d341013 2160
6320cdc0 2161If you want the code to die instead, replace "try" with "only":
b8884ce4 2162
6320cdc0 2163 use Math::BigRat only => 'Foo,Math::BigInt::Bar';
7d341013 2164
184f15d5
JH
2165=head1 METHODS
2166
3c4b39be 2167Any methods not listed here are derived from Math::BigFloat (or
6de7f0cc
JH
2168Math::BigInt), so make sure you check these two modules for further
2169information.
2170
6320cdc0
SH
2171=over
2172
2173=item new()
184f15d5 2174
6320cdc0 2175 $x = Math::BigRat->new('1/3');
184f15d5
JH
2176
2177Create a new Math::BigRat object. Input can come in various forms:
2178
6320cdc0
SH
2179 $x = Math::BigRat->new(123); # scalars
2180 $x = Math::BigRat->new('inf'); # infinity
2181 $x = Math::BigRat->new('123.3'); # float
2182 $x = Math::BigRat->new('1/3'); # simple string
2183 $x = Math::BigRat->new('1 / 3'); # spaced
2184 $x = Math::BigRat->new('1 / 0.1'); # w/ floats
2185 $x = Math::BigRat->new(Math::BigInt->new(3)); # BigInt
2186 $x = Math::BigRat->new(Math::BigFloat->new('3.1')); # BigFloat
2187 $x = Math::BigRat->new(Math::BigInt::Lite->new('2')); # BigLite
184f15d5 2188
6320cdc0
SH
2189 # You can also give D and N as different objects:
2190 $x = Math::BigRat->new(
2191 Math::BigInt->new(-123),
2192 Math::BigInt->new(7),
2193 ); # => -123/7
b68b7ab1 2194
6320cdc0 2195=item numerator()
184f15d5 2196
6320cdc0 2197 $n = $x->numerator();
184f15d5
JH
2198
2199Returns a copy of the numerator (the part above the line) as signed BigInt.
2200
6320cdc0 2201=item denominator()
ccbfef19 2202
6320cdc0 2203 $d = $x->denominator();
184f15d5
JH
2204
2205Returns a copy of the denominator (the part under the line) as positive BigInt.
2206
6320cdc0 2207=item parts()
184f15d5 2208
6320cdc0 2209 ($n, $d) = $x->parts();
184f15d5
JH
2210
2211Return a list consisting of (signed) numerator and (unsigned) denominator as
2212BigInts.
2213
6320cdc0 2214=item numify()
b8884ce4 2215
6320cdc0 2216 my $y = $x->numify();
b8884ce4
T
2217
2218Returns the object as a scalar. This will lose some data if the object
2219cannot be represented by a normal Perl scalar (integer or float), so
3cc1ad36 2220use L</as_int()> or L</as_float()> instead.
b8884ce4
T
2221
2222This routine is automatically used whenever a scalar is required:
2223
6320cdc0
SH
2224 my $x = Math::BigRat->new('3/1');
2225 @array = (0, 1, 2, 3);
2226 $y = $array[$x]; # set $y to 3
b8884ce4 2227
3cc1ad36
SH
2228=item as_int()
2229
2230=item as_number()
6de7f0cc 2231
6320cdc0
SH
2232 $x = Math::BigRat->new('13/7');
2233 print $x->as_int(), "\n"; # '1'
b68b7ab1
T
2234
2235Returns a copy of the object as BigInt, truncated to an integer.
7d341013 2236
b68b7ab1
T
2237C<as_number()> is an alias for C<as_int()>.
2238
6320cdc0 2239=item as_float()
4de3d162 2240
6320cdc0
SH
2241 $x = Math::BigRat->new('13/7');
2242 print $x->as_float(), "\n"; # '1'
4de3d162 2243
6320cdc0
SH
2244 $x = Math::BigRat->new('2/3');
2245 print $x->as_float(5), "\n"; # '0.66667'
4de3d162
T
2246
2247Returns a copy of the object as BigFloat, preserving the
2248accuracy as wanted, or the default of 40 digits.
2249
2250This method was added in v0.22 of Math::BigRat (April 2008).
2251
6320cdc0 2252=item as_hex()
b68b7ab1 2253
6320cdc0
SH
2254 $x = Math::BigRat->new('13');
2255 print $x->as_hex(), "\n"; # '0xd'
b68b7ab1 2256
ccbfef19 2257Returns the BigRat as hexadecimal string. Works only for integers.
b68b7ab1 2258
6320cdc0 2259=item as_bin()
b68b7ab1 2260
6320cdc0
SH
2261 $x = Math::BigRat->new('13');
2262 print $x->as_bin(), "\n"; # '0x1101'
b68b7ab1 2263
ccbfef19 2264Returns the BigRat as binary string. Works only for integers.
6de7f0cc 2265
6320cdc0 2266=item as_oct()
b8884ce4 2267
6320cdc0
SH
2268 $x = Math::BigRat->new('13');
2269 print $x->as_oct(), "\n"; # '015'
b8884ce4 2270
ccbfef19 2271Returns the BigRat as octal string. Works only for integers.
b8884ce4 2272
6320cdc0
SH
2273=item from_hex()
2274
2275 my $h = Math::BigRat->from_hex('0x10');
2276
2277Create a BigRat from a hexadecimal number in string form.
2278
2279=item from_oct()
2280
2281 my $o = Math::BigRat->from_oct('020');
2282
2283Create a BigRat from an octal number in string form.
2284
2285=item from_bin()
2286
2287 my $b = Math::BigRat->from_bin('0b10000000');
2288
2289Create a BigRat from an binary number in string form.
2290
2291=item bnan()
2292
2293 $x = Math::BigRat->bnan();
2294
2295Creates a new BigRat object representing NaN (Not A Number).
2296If used on an object, it will set it to NaN:
2297
2298 $x->bnan();
b8884ce4 2299
6320cdc0 2300=item bzero()
b8884ce4 2301
6320cdc0 2302 $x = Math::BigRat->bzero();
b8884ce4 2303
6320cdc0
SH
2304Creates a new BigRat object representing zero.
2305If used on an object, it will set it to zero:
b8884ce4 2306
6320cdc0
SH
2307 $x->bzero();
2308
2309=item binf()
2310
2311 $x = Math::BigRat->binf($sign);
2312
2313Creates a new BigRat object representing infinity. The optional argument is
2314either '-' or '+', indicating whether you want infinity or minus infinity.
2315If used on an object, it will set it to infinity:
2316
2317 $x->binf();
2318 $x->binf('-');
2319
2320=item bone()
2321
2322 $x = Math::BigRat->bone($sign);
2323
2324Creates a new BigRat object representing one. The optional argument is
2325either '-' or '+', indicating whether you want one or minus one.
2326If used on an object, it will set it to one:
2327
2328 $x->bone(); # +1
2329 $x->bone('-'); # -1
2330
2331=item length()
2332
2333 $len = $x->length();
b8884ce4 2334
c4a6f826 2335Return the length of $x in digits for integer values.
b8884ce4 2336
6320cdc0 2337=item digit()
b8884ce4 2338
6320cdc0
SH
2339 print Math::BigRat->new('123/1')->digit(1); # 1
2340 print Math::BigRat->new('123/1')->digit(-1); # 3
b8884ce4
T
2341
2342Return the N'ths digit from X when X is an integer value.
2343
6320cdc0 2344=item bnorm()
b8884ce4 2345
6320cdc0 2346 $x->bnorm();
b8884ce4
T
2347
2348Reduce the number to the shortest form. This routine is called
2349automatically whenever it is needed.
2350
6320cdc0 2351=item bfac()
6de7f0cc 2352
6320cdc0 2353 $x->bfac();
6de7f0cc 2354
a4e2b1c6 2355Calculates the factorial of $x. For instance:
6de7f0cc 2356
6320cdc0
SH
2357 print Math::BigRat->new('3/1')->bfac(), "\n"; # 1*2*3
2358 print Math::BigRat->new('5/1')->bfac(), "\n"; # 1*2*3*4*5
184f15d5 2359
7d341013 2360Works currently only for integers.
6de7f0cc 2361
6320cdc0 2362=item bround()/round()/bfround()
6de7f0cc 2363
a4e2b1c6 2364Are not yet implemented.
6de7f0cc 2365
6320cdc0 2366=item bmod()
990fb837 2367
6320cdc0 2368 $x->bmod($y);
990fb837 2369
3f185657
PJA
2370Returns $x modulo $y. When $x is finite, and $y is finite and non-zero, the
2371result is identical to the remainder after floored division (F-division). If,
2372in addition, both $x and $y are integers, the result is identical to the result
2373from Perl's % operator.
990fb837 2374
6320cdc0
SH
2375=item bmodinv()
2376
2377 $x->bmodinv($mod); # modular multiplicative inverse
2378
2379Returns the multiplicative inverse of C<$x> modulo C<$mod>. If
2380
2381 $y = $x -> copy() -> bmodinv($mod)
2382
2383then C<$y> is the number closest to zero, and with the same sign as C<$mod>,
2384satisfying
2385
2386 ($x * $y) % $mod = 1 % $mod
2387
2388If C<$x> and C<$y> are non-zero, they must be relative primes, i.e.,
2389C<bgcd($y, $mod)==1>. 'C<NaN>' is returned when no modular multiplicative
2390inverse exists.
b8884ce4 2391
6320cdc0
SH
2392=item bmodpow()
2393
2394 $num->bmodpow($exp,$mod); # modular exponentiation
2395 # ($num**$exp % $mod)
2396
2397Returns the value of C<$num> taken to the power C<$exp> in the modulus
2398C<$mod> using binary exponentiation. C<bmodpow> is far superior to
2399writing
2400
2401 $num ** $exp % $mod
2402
2403because it is much faster - it reduces internal variables into
2404the modulus whenever possible, so it operates on smaller numbers.
2405
2406C<bmodpow> also supports negative exponents.
2407
2408 bmodpow($num, -1, $mod)
2409
2410is exactly equivalent to
2411
2412 bmodinv($num, $mod)
2413
2414=item bneg()
2415
2416 $x->bneg();
b8884ce4
T
2417
2418Used to negate the object in-place.
2419
6320cdc0 2420=item is_one()
7d341013 2421
6320cdc0 2422 print "$x is 1\n" if $x->is_one();
7d341013
T
2423
2424Return true if $x is exactly one, otherwise false.
2425
6320cdc0 2426=item is_zero()
7d341013 2427
6320cdc0 2428 print "$x is 0\n" if $x->is_zero();
7d341013
T
2429
2430Return true if $x is exactly zero, otherwise false.
2431
6320cdc0 2432=item is_pos()/is_positive()
7d341013 2433
6320cdc0 2434 print "$x is >= 0\n" if $x->is_positive();
7d341013
T
2435
2436Return true if $x is positive (greater than or equal to zero), otherwise
2437false. Please note that '+inf' is also positive, while 'NaN' and '-inf' aren't.
2438
b68b7ab1
T
2439C<is_positive()> is an alias for C<is_pos()>.
2440
6320cdc0 2441=item is_neg()/is_negative()
7d341013 2442
6320cdc0 2443 print "$x is < 0\n" if $x->is_negative();
7d341013
T
2444
2445Return true if $x is negative (smaller than zero), otherwise false. Please
2446note that '-inf' is also negative, while 'NaN' and '+inf' aren't.
2447
b68b7ab1
T
2448C<is_negative()> is an alias for C<is_neg()>.
2449
6320cdc0 2450=item is_int()
7d341013 2451
6320cdc0 2452 print "$x is an integer\n" if $x->is_int();
7d341013
T
2453
2454Return true if $x has a denominator of 1 (e.g. no fraction parts), otherwise
2455false. Please note that '-inf', 'inf' and 'NaN' aren't integer.
2456
6320cdc0 2457=item is_odd()
7d341013 2458
6320cdc0 2459 print "$x is odd\n" if $x->is_odd();
7d341013
T
2460
2461Return true if $x is odd, otherwise false.
2462
6320cdc0 2463=item is_even()
7d341013 2464
6320cdc0 2465 print "$x is even\n" if $x->is_even();
7d341013
T
2466
2467Return true if $x is even, otherwise false.
2468
6320cdc0 2469=item bceil()
7d341013 2470
6320cdc0 2471 $x->bceil();
7d341013
T
2472
2473Set $x to the next bigger integer value (e.g. truncate the number to integer
2474and then increment it by one).
2475
6320cdc0 2476=item bfloor()
ccbfef19 2477
6320cdc0 2478 $x->bfloor();
7d341013
T
2479
2480Truncate $x to an integer value.
6de7f0cc 2481
6320cdc0
SH
2482=item bint()
2483
2484 $x->bint();
2485
2486Round $x towards zero.
ccbfef19 2487
6320cdc0
SH
2488=item bsqrt()
2489
2490 $x->bsqrt();
7afd7a91
T
2491
2492Calculate the square root of $x.
2493
6320cdc0 2494=item broot()
ccbfef19 2495
6320cdc0 2496 $x->broot($n);
b8884ce4
T
2497
2498Calculate the N'th root of $x.
2499
6320cdc0 2500=item badd()
3f185657 2501
6320cdc0 2502 $x->badd($y);
3f185657
PJA
2503
2504Adds $y to $x and returns the result.
2505
6320cdc0 2506=item bmul()
3f185657 2507
6320cdc0 2508 $x->bmul($y);
3f185657
PJA
2509
2510Multiplies $y to $x and returns the result.
2511
6320cdc0 2512=item bsub()
3f185657 2513
6320cdc0 2514 $x->bsub($y);
3f185657
PJA
2515
2516Subtracts $y from $x and returns the result.
2517
6320cdc0 2518=item bdiv()
3f185657 2519
6320cdc0
SH
2520 $q = $x->bdiv($y);
2521 ($q, $r) = $x->bdiv($y);
3f185657
PJA
2522
2523In scalar context, divides $x by $y and returns the result. In list context,
2524does floored division (F-division), returning an integer $q and a remainder $r
2525so that $x = $q * $y + $r. The remainer (modulo) is equal to what is returned
7deec013 2526by C<< $x->bmod($y) >>.
3f185657 2527
6320cdc0 2528=item bdec()
3f185657 2529
6320cdc0 2530 $x->bdec();
3f185657
PJA
2531
2532Decrements $x by 1 and returns the result.
2533
6320cdc0 2534=item binc()
3f185657 2535
6320cdc0 2536 $x->binc();
b8884ce4 2537
3f185657 2538Increments $x by 1 and returns the result.
b8884ce4 2539
6320cdc0 2540=item copy()
b8884ce4 2541
6320cdc0 2542 my $z = $x->copy();
b8884ce4
T
2543
2544Makes a deep copy of the object.
2545
2546Please see the documentation in L<Math::BigInt> for further details.
2547
6320cdc0 2548=item bstr()/bsstr()
b8884ce4 2549
6320cdc0
SH
2550 my $x = Math::BigRat->new('8/4');
2551 print $x->bstr(), "\n"; # prints 1/2
2552 print $x->bsstr(), "\n"; # prints 1/2
b8884ce4 2553
c4a6f826 2554Return a string representing this object.
b8884ce4 2555
6320cdc0 2556=item bcmp()
b8884ce4 2557
6320cdc0 2558 $x->bcmp($y);
b8884ce4 2559
6320cdc0
SH
2560Compares $x with $y and takes the sign into account.
2561Returns -1, 0, 1 or undef.
2562
2563=item bacmp()
2564
2565 $x->bacmp($y);
b8884ce4 2566
6320cdc0
SH
2567Compares $x with $y while ignoring their sign. Returns -1, 0, 1 or undef.
2568
2569=item beq()
2570
2571 $x -> beq($y);
2572
2573Returns true if and only if $x is equal to $y, and false otherwise.
2574
2575=item bne()
2576
2577 $x -> bne($y);
2578
2579Returns true if and only if $x is not equal to $y, and false otherwise.
2580
2581=item blt()
2582
2583 $x -> blt($y);
2584
2585Returns true if and only if $x is equal to $y, and false otherwise.
2586
2587=item ble()
2588
2589 $x -> ble($y);
2590
2591Returns true if and only if $x is less than or equal to $y, and false
2592otherwise.
2593
2594=item bgt()
2595
2596 $x -> bgt($y);
2597
2598Returns true if and only if $x is greater than $y, and false otherwise.
2599
2600=item bge()
2601
2602 $x -> bge($y);
2603
2604Returns true if and only if $x is greater than or equal to $y, and false
2605otherwise.
2606
2607=item blsft()/brsft()
b8884ce4
T
2608
2609Used to shift numbers left/right.
2610
2611Please see the documentation in L<Math::BigInt> for further details.
2612
6320cdc0
SH
2613=item band()
2614
2615 $x->band($y); # bitwise and
2616
2617=item bior()
2618
2619 $x->bior($y); # bitwise inclusive or
2620
2621=item bxor()
2622
2623 $x->bxor($y); # bitwise exclusive or
b8884ce4 2624
6320cdc0
SH
2625=item bnot()
2626
2627 $x->bnot(); # bitwise not (two's complement)
2628
2629=item bpow()
2630
2631 $x->bpow($y);
b8884ce4
T
2632
2633Compute $x ** $y.
2634
2635Please see the documentation in L<Math::BigInt> for further details.
2636
6320cdc0
SH
2637=item blog()
2638
2639 $x->blog($base, $accuracy); # logarithm of x to the base $base
116a1b2f 2640
6320cdc0
SH
2641If C<$base> is not defined, Euler's number (e) is used:
2642
2643 print $x->blog(undef, 100); # log(x) to 100 digits
2644
2645=item bexp()
2646
2647 $x->bexp($accuracy); # calculate e ** X
116a1b2f
SP
2648
2649Calculates two integers A and B so that A/B is equal to C<e ** $x>, where C<e> is
2650Euler's number.
2651
2652This method was added in v0.20 of Math::BigRat (May 2007).
2653
3d6c5fec 2654See also C<blog()>.
116a1b2f 2655
6320cdc0 2656=item bnok()
116a1b2f 2657
6320cdc0 2658 $x->bnok($y); # x over y (binomial coefficient n over k)
116a1b2f
SP
2659
2660Calculates the binomial coefficient n over k, also called the "choose"
2661function. The result is equivalent to:
2662
6320cdc0
SH
2663 ( n ) n!
2664 | - | = -------
2665 ( k ) k!(n-k)!
116a1b2f
SP
2666
2667This method was added in v0.20 of Math::BigRat (May 2007).
2668
6320cdc0 2669=item config()
990fb837 2670
3cc1ad36
SH
2671 Math::BigRat->config("trap_nan" => 1); # set
2672 $accu = Math::BigRat->config("accuracy"); # get
990fb837 2673
3cc1ad36
SH
2674Set or get configuration parameter values. Read-only parameters are marked as
2675RO. Read-write parameters are marked as RW. The following parameters are
2676supported.
990fb837 2677
3cc1ad36 2678 Parameter RO/RW Description
6320cdc0
SH
2679 Example
2680 ============================================================
3cc1ad36 2681 lib RO Name of the math backend library
6320cdc0 2682 Math::BigInt::Calc
3cc1ad36 2683 lib_version RO Version of the math backend library
6320cdc0
SH
2684 0.30
2685 class RO The class of config you just called
2686 Math::BigRat
2687 version RO version number of the class you used
2688 0.10
2689 upgrade RW To which class numbers are upgraded
2690 undef
2691 downgrade RW To which class numbers are downgraded
2692 undef
2693 precision RW Global precision
2694 undef
2695 accuracy RW Global accuracy
2696 undef
2697 round_mode RW Global round mode
2698 even
3cc1ad36 2699 div_scale RW Fallback accuracy for div, sqrt etc.
6320cdc0 2700 40
3cc1ad36 2701 trap_nan RW Trap NaNs
6320cdc0 2702 undef
3cc1ad36 2703 trap_inf RW Trap +inf/-inf
6320cdc0 2704 undef
990fb837 2705
6320cdc0 2706=back
4de3d162 2707
a4e2b1c6 2708=head1 BUGS
6de7f0cc 2709
a7752796
PJA
2710Please report any bugs or feature requests to
2711C<bug-math-bigrat at rt.cpan.org>, or through the web interface at
2712L<https://rt.cpan.org/Ticket/Create.html?Queue=Math-BigRat>
2713(requires login).
2714We will be notified, and then you'll automatically be notified of progress on
2715your bug as I make changes.
2716
2717=head1 SUPPORT
2718
2719You can find documentation for this module with the perldoc command.
2720
2721 perldoc Math::BigRat
2722
2723You can also look for information at:
2724
2725=over 4
2726
7deec013 2727=item * GitHub
a7752796 2728
7deec013 2729L<https://github.com/pjacklam/p5-Math-BigRat>
a7752796 2730
7deec013 2731=item * RT: CPAN's request tracker
7d341013 2732
7deec013 2733L<https://rt.cpan.org/Dist/Display.html?Name=Math-BigRat>
7d341013 2734
7deec013 2735=item * MetaCPAN
7d341013 2736
7deec013 2737L<https://metacpan.org/release/Math-BigRat>
7d341013 2738
a7752796 2739=item * CPAN Testers Matrix
7d341013 2740
a7752796 2741L<http://matrix.cpantesters.org/?dist=Math-BigRat>
7d341013 2742
7deec013 2743=item * CPAN Ratings
a7752796 2744
7deec013 2745L<https://cpanratings.perl.org/dist/Math-BigRat>
7afd7a91 2746
7d341013 2747=back
184f15d5
JH
2748
2749=head1 LICENSE
2750
2751This program is free software; you may redistribute it and/or modify it under
2752the same terms as Perl itself.
2753
2754=head1 SEE ALSO
2755
a7752796
PJA
2756L<bigrat>, L<Math::BigFloat> and L<Math::BigInt> as well as the backends
2757L<Math::BigInt::FastCalc>, L<Math::BigInt::GMP>, and L<Math::BigInt::Pari>.
184f15d5
JH
2758
2759=head1 AUTHORS
2760
0b299427
SH
2761=over 4
2762
2763=item *
2764
2765Tels L<http://bloodgate.com/> 2001-2009.
c6c613ed 2766
0b299427
SH
2767=item *
2768
7deec013 2769Maintained by Peter John Acklam <pjacklam@gmail.com> 2011-
0b299427
SH
2770
2771=back
184f15d5
JH
2772
2773=cut