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