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