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