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