File Coverage

blib/lib/Math/BigNum.pm
Criterion Covered Total %
statement 12 14 85.7
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 17 19 89.4


line stmt bran cond sub pod time code
1             package Math::BigNum;
2              
3 1     1   13544 use 5.014;
  1         3  
4 1     1   3 use strict;
  1         2  
  1         15  
5 1     1   4 use warnings;
  1         4  
  1         26  
6              
7 1     1   3 no warnings 'numeric';
  1         1  
  1         22  
8              
9 1     1   203 use Math::GMPq qw();
  0            
  0            
10             use Math::GMPz qw();
11             use Math::MPFR qw();
12              
13             use Class::Multimethods qw();
14              
15             #<<<
16             use constant {
17             MAX_UI => defined(&Math::GMPq::_ulong_max)
18             ? Math::GMPq::_ulong_max()
19             : unpack('I', pack('I', -1)),
20              
21             MIN_SI => defined(&Math::GMPq::_long_min)
22             ? Math::GMPq::_long_min()
23             : -(unpack('I', pack('I', -1)) >> 1),
24             };
25             #>>>
26              
27             our $VERSION = '0.19';
28              
29             =encoding utf8
30              
31             =head1 NAME
32              
33             Math::BigNum - Arbitrary size precision for integers, rationals and floating-point numbers.
34              
35             =head1 VERSION
36              
37             Version 0.19
38              
39             =head1 SYNOPSIS
40              
41             use 5.014;
42             use Math::BigNum qw(:constant);
43              
44             # Big numbers
45             say ((100->fac + 1) / 2);
46             # => 466631077219720763408496194281333502453579841321908107 \
47             # 342964819476087999966149578044707319880782591431268489 \
48             # 60413611879125592605458432000000000000000000000000.5
49              
50             # Small numbers
51             say sqrt(1 / 100->fac); # => 1.03513781117562647132049[...]e-79
52              
53             # Rational numbers
54             my $x = 2/3;
55             say $x*3; # => 2
56             say 2/$x; # => 3
57             say $x->as_frac; # => "2/3"
58              
59             # Floating-point numbers
60             say "equal" if (1.1 + 2.2 == 3.3); # => "equal"
61              
62             =head1 DESCRIPTION
63              
64             Math::BigNum provides a transparent interface to Math::GMPz, Math::GMPq and Math::MPFR, focusing
65             on performance and easy-to-use. In most cases, it can be used as a drop-in replacement for the
66             L and L pragmas.
67              
68             =head1 MOTIVATION
69              
70             This module came into existence as a response to Dana Jacobsen's request for a transparent
71             interface to L and L, which he talked about at the YAPC NA, in 2015.
72              
73             See his great presentation at: L.
74              
75             The main aim of this module is to provide a fast and correct alternative to L,
76             L and L, as well as to L, L and L pragmas.
77              
78             =head1 HOW IT WORKS
79              
80             Math::BigNum tries really hard to do the right thing and as efficiently as possible.
81             For example, when computing C, it first checks to see if C and C are integers,
82             so it can optimize the operation to integer exponentiation, by calling the corresponding
83             I function. When only C is an integer, it does rational exponentiation based on the
84             identity: I<(a/b)^n = a^n / b^n>. Otherwise, it will fallback to floating-point exponentiation,
85             using the corresponding I function.
86              
87             All numbers in Math::BigNum are stored as rational L objects. Each operation,
88             outside the functions provided by L, is done by converting the internal objects to
89             L or L objects and calling the corresponding functions, converting
90             the results back to L objects, without loosing any precision in the process.
91              
92             =head1 IMPORT / EXPORT
93              
94             Math::BigNum does not export anything by default, but it recognizes the followings:
95              
96             :constant # will make any number a Math::BigNum object
97             # it will also export the "Inf" and "NaN" constants,
98             # which represent +Infinity and NaN special values
99              
100             :all # export everything that is exportable
101             PREC n # set the global precision to the value of `n`
102              
103             B
104              
105             e # "e" constant (2.7182...)
106             pi # "pi" constant (3.1415...)
107             tau # "tau" constant (which is: 2*pi)
108             phi # Golden ratio constant (1.618...)
109             G # Catalan's constant (0.91596...)
110             Y # Euler-Mascheroni constant (0.57721...)
111             Inf # +Infinity constant
112             NaN # Not-a-Number constant
113              
114             B
115              
116             factorial(n) # product of first n integers: n!
117             primorial(n) # product of primes <= n
118             binomial(n,k) # binomial coefficient
119             fibonacci(n) # nth-Fibonacci number
120             lucas(n) # nth-Lucas number
121             ipow(a,k) # integer exponentiation: a^k
122              
123             B this functions are designed and optimized for native Perl integers as input.
124              
125             The syntax for importing something, is:
126              
127             use Math::BigNum qw(:constant pi factorial);
128             say cos(2*pi); # => 1
129             say factorial(5); # => 120
130              
131             B C<:constant> is lexical to the current scope only.
132              
133             The syntax for disabling the C<:constant> behavior in the current scope, is:
134              
135             no Math::BigNum; # :constant will be disabled in the current scope
136              
137             =head1 PRECISION
138              
139             The default precision for floating-point numbers is 200 bits, which is equivalent with about
140             50 digits of precision in base 10.
141              
142             The precision can be changed by modifying the C<$Math::BigNum::PREC> variable, such as:
143              
144             local $Math::BigNum::PREC = 1024;
145              
146             or by specifying the precision at import (this sets the precision globally):
147              
148             use Math::BigNum PREC => 1024;
149              
150             However, an important thing to take into account, unlike the L objects, Math::BigNum
151             objects do not have a fixed precision stored inside. Rather, they can grow or shrink dynamically,
152             regardless of the global precision.
153              
154             The global precision controls only the precision of the floating-point functions and the
155             stringification of floating-point numbers.
156              
157             For example, if we change the precision to 3 decimal digits (where C<4> is the conversion factor),
158             we get the following results:
159              
160             local $Math::BigNum::PREC = 3*4;
161             say sqrt(2); # => 1.414
162             say 98**7; # => 86812553324672
163             say 1 / 98**7 # => 1.15e-14
164              
165             As shown above, integers do not obey the global precision, because they can grow or shrink
166             dynamically, without a specific limit. This is true for rational numbers as well.
167              
168             A rational number never losses precision in rational operations, therefore if we say:
169              
170             my $x = 1 / 3;
171             say $x * 3; # => 1
172             say 1 / $x; # => 3
173             say 3 / $x; # => 9
174              
175             ...the results are 100% exact.
176              
177             =head1 NOTATIONS
178              
179             Methods that begin with a B followed by the actual name (e.g.: C), are mutable
180             methods that change the self object in-place, while their counter-parts (e.g.: C)
181             do not. Instead, they will create and return a new object.
182              
183             In addition, Math::BigNum features another kind of methods that begin with an B followed by
184             the actual name (e.g.: C). This methods do integer operations, by first
185             truncating their arguments to integers, whenever needed.
186              
187             Lastly, Math::BigNum implements another kind of methods that begin with an B followed by the actual name (e.g.: C).
188             This methods do floating-point operations and are usually faster than their rational counterparts when invoked on very large or very small real-numbers.
189              
190             The returned types are noted as follows:
191              
192             BigNum # a "Math::BigNum" object
193             Inf # a "Math::BigNum::Inf" object
194             Nan # a "Math::BigNum::Nan" object
195             Scalar # a Perl number or string
196             Bool # true or false (actually: 1 or 0)
197              
198             When two or more types are separated with pipe characters (B<|>), it means that the
199             corresponding function can return any of the specified types.
200              
201             =head1 PERFORMANCE
202              
203             The performance varies greatly, but, in most cases, Math::BigNum is between 2x up to 10x
204             faster than L with the B backend, and about 100x faster than L
205             without the B backend (to be modest).
206              
207             Math::BigNum is fast because of the following facts:
208              
209             =over 4
210              
211             =item *
212              
213             minimal overhead in object creation.
214              
215             =item *
216              
217             minimal Perl code is executed per operation.
218              
219             =item *
220              
221             the B and B libraries are extremely efficient.
222              
223             =back
224              
225             To achieve the best performance, try to follow this rules:
226              
227             =over 4
228              
229             =item *
230              
231             use the B methods whenever you can.
232              
233             =item *
234              
235             use the B methods wherever applicable.
236              
237             =item *
238              
239             use the B methods when accuracy is not important.
240              
241             =item *
242              
243             pass Perl numbers as arguments to methods, if you can.
244              
245             =item *
246              
247             avoid the stringification of non-integer Math::BigNum objects.
248              
249             =item *
250              
251             don't use B followed by a B method! Just leave out the B.
252              
253             =back
254              
255             =cut
256              
257             our ($ROUND, $PREC);
258              
259             BEGIN {
260             $ROUND = Math::MPFR::MPFR_RNDN();
261             $PREC = 200; # too little?
262             }
263              
264             use Math::BigNum::Inf qw();
265             use Math::BigNum::Nan qw();
266              
267             state $MONE = do {
268             my $r = Math::GMPq::Rmpq_init_nobless();
269             Math::GMPq::Rmpq_set_si($r, -1, 1);
270             $r;
271             };
272              
273             state $ZERO = do {
274             my $r = Math::GMPq::Rmpq_init_nobless();
275             Math::GMPq::Rmpq_set_ui($r, 0, 1);
276             $r;
277             };
278              
279             state $ONE = do {
280             my $r = Math::GMPq::Rmpq_init_nobless();
281             Math::GMPq::Rmpq_set_ui($r, 1, 1);
282             $r;
283             };
284              
285             state $ONE_Z = Math::GMPz::Rmpz_init_set_ui_nobless(1);
286              
287             use overload
288             '""' => \&stringify,
289             '0+' => \&numify,
290             bool => \&boolify,
291              
292             '=' => \©,
293              
294             # Some shortcuts for speed
295             '+=' => sub { $_[0]->badd($_[1]) },
296             '-=' => sub { $_[0]->bsub($_[1]) },
297             '*=' => sub { $_[0]->bmul($_[1]) },
298             '/=' => sub { $_[0]->bdiv($_[1]) },
299             '%=' => sub { $_[0]->bmod($_[1]) },
300             '**=' => sub { $_[0]->bpow($_[1]) },
301              
302             '^=' => sub { $_[0]->bxor($_[1]) },
303             '&=' => sub { $_[0]->band($_[1]) },
304             '|=' => sub { $_[0]->bior($_[1]) },
305             '<<=' => sub { $_[0]->blsft($_[1]) },
306             '>>=' => sub { $_[0]->brsft($_[1]) },
307              
308             '+' => sub { $_[0]->add($_[1]) },
309             '*' => sub { $_[0]->mul($_[1]) },
310              
311             '==' => sub { $_[0]->eq($_[1]) },
312             '!=' => sub { $_[0]->ne($_[1]) },
313             '&' => sub { $_[0]->and($_[1]) },
314             '|' => sub { $_[0]->ior($_[1]) },
315             '^' => sub { $_[0]->xor($_[1]) },
316             '~' => \¬,
317              
318             '++' => \&binc,
319             '--' => \&bdec,
320              
321             '>' => sub { Math::BigNum::gt($_[2] ? ($_[1], $_[0]) : ($_[0], $_[1])) },
322             '>=' => sub { Math::BigNum::ge($_[2] ? ($_[1], $_[0]) : ($_[0], $_[1])) },
323             '<' => sub { Math::BigNum::lt($_[2] ? ($_[1], $_[0]) : ($_[0], $_[1])) },
324             '<=' => sub { Math::BigNum::le($_[2] ? ($_[1], $_[0]) : ($_[0], $_[1])) },
325             '<=>' => sub { Math::BigNum::cmp($_[2] ? ($_[1], $_[0]) : ($_[0], $_[1])) },
326              
327             '>>' => sub { Math::BigNum::rsft($_[2] ? ($_[1], $_[0]) : ($_[0], $_[1])) },
328             '<<' => sub { Math::BigNum::lsft($_[2] ? ($_[1], $_[0]) : ($_[0], $_[1])) },
329              
330             '**' => sub { Math::BigNum::pow($_[2] ? ($_[1], $_[0]) : ($_[0], $_[1])) },
331             '-' => sub { Math::BigNum::sub($_[2] ? ($_[1], $_[0]) : ($_[0], $_[1])) },
332             '/' => sub { Math::BigNum::div($_[2] ? ($_[1], $_[0]) : ($_[0], $_[1])) },
333             '%' => sub { Math::BigNum::mod($_[2] ? ($_[1], $_[0]) : ($_[0], $_[1])) },
334              
335             atan2 => sub { Math::BigNum::atan2($_[2] ? ($_[1], $_[0]) : ($_[0], $_[1])) },
336              
337             eq => sub { "$_[0]" eq "$_[1]" },
338             ne => sub { "$_[0]" ne "$_[1]" },
339              
340             cmp => sub { $_[2] ? "$_[1]" cmp $_[0]->stringify : $_[0]->stringify cmp "$_[1]" },
341              
342             neg => \&neg,
343             sin => \&sin,
344             cos => \&cos,
345             exp => \&exp,
346             log => \&ln,
347             int => \&int,
348             abs => \&abs,
349             sqrt => \&sqrt;
350              
351             {
352             my $binomial = sub {
353             my ($n, $k) = @_;
354              
355             (defined($n) and defined($k)) or return nan();
356             ref($n) eq __PACKAGE__ and return $n->binomial($k);
357              
358             (CORE::int($k) eq $k and $k >= MIN_SI and $k <= MAX_UI)
359             || return Math::BigNum->new($n)->binomial(Math::BigNum->new($k));
360              
361             my $n_ui = (CORE::int($n) eq $n and $n >= 0 and $n <= MAX_UI);
362             my $k_ui = $k >= 0;
363              
364             my $z = Math::GMPz::Rmpz_init();
365              
366             if ($n_ui and $k_ui) {
367             Math::GMPz::Rmpz_bin_uiui($z, $n, $k);
368             }
369             else {
370             eval { Math::GMPz::Rmpz_set_str($z, "$n", 10); 1 } // return Math::BigNum->new($n)->binomial($k);
371             $k_ui
372             ? Math::GMPz::Rmpz_bin_ui($z, $z, $k)
373             : Math::GMPz::Rmpz_bin_si($z, $z, $k);
374             }
375              
376             _mpz2big($z);
377             };
378              
379             my $factorial = sub {
380             my ($n) = @_;
381             $n // return nan();
382             ref($n) eq __PACKAGE__ and return $n->fac;
383             if (CORE::int($n) eq $n and $n >= 0 and $n <= MAX_UI) {
384             my $z = Math::GMPz::Rmpz_init();
385             Math::GMPz::Rmpz_fac_ui($z, $n);
386             _mpz2big($z);
387             }
388             else {
389             Math::BigNum->new($n)->fac;
390             }
391             };
392              
393             my $primorial = sub {
394             my ($n) = @_;
395             $n // return nan();
396             ref($n) eq __PACKAGE__ and return $n->primorial;
397             if (CORE::int($n) eq $n and $n >= 0 and $n <= MAX_UI) {
398             my $z = Math::GMPz::Rmpz_init();
399             Math::GMPz::Rmpz_primorial_ui($z, $n);
400             _mpz2big($z);
401             }
402             else {
403             Math::BigNum->new($n)->primorial;
404             }
405             };
406              
407             my $fibonacci = sub {
408             my ($n) = @_;
409             $n // return nan();
410             ref($n) eq __PACKAGE__ and return $n->fib;
411             if (CORE::int($n) eq $n and $n >= 0 and $n <= MAX_UI) {
412             my $z = Math::GMPz::Rmpz_init();
413             Math::GMPz::Rmpz_fib_ui($z, $n);
414             _mpz2big($z);
415             }
416             else {
417             Math::BigNum->new($n)->fib;
418             }
419             };
420              
421             my $lucas = sub {
422             my ($n) = @_;
423             $n // return nan();
424             ref($n) eq __PACKAGE__ and return $n->lucas;
425             if (CORE::int($n) eq $n and $n >= 0 and $n <= MAX_UI) {
426             my $z = Math::GMPz::Rmpz_init();
427             Math::GMPz::Rmpz_lucnum_ui($z, $n);
428             _mpz2big($z);
429             }
430             else {
431             Math::BigNum->new($n)->lucas;
432             }
433             };
434              
435             my $ipow = sub {
436             my ($n, $k) = @_;
437              
438             (defined($n) and defined($k)) or return nan();
439             ref($n) eq __PACKAGE__ and return $n->ipow($k);
440              
441             (CORE::int($n) eq $n and CORE::int($k) eq $k and $n <= MAX_UI and $k <= MAX_UI and $n >= MIN_SI and $k >= 0)
442             || return Math::BigNum->new($n)->ipow($k);
443              
444             my $z = Math::GMPz::Rmpz_init();
445             Math::GMPz::Rmpz_ui_pow_ui($z, CORE::abs($n), $k);
446             Math::GMPz::Rmpz_neg($z, $z) if ($n < 0 and $k % 2);
447             _mpz2big($z);
448             };
449              
450             my %constants = (
451             e => \&e,
452             phi => \&phi,
453             tau => \&tau,
454             pi => \&pi,
455             Y => \&Y,
456             G => \&G,
457             Inf => \&inf,
458             NaN => \&nan,
459             );
460              
461             my %functions = (
462             binomial => $binomial,
463             factorial => $factorial,
464             primorial => $primorial,
465             fibonacci => $fibonacci,
466             lucas => $lucas,
467             ipow => $ipow,
468             );
469              
470             sub import {
471             shift;
472              
473             my $caller = caller(0);
474              
475             while (@_) {
476             my $name = shift(@_);
477              
478             if ($name eq ':constant') {
479             overload::constant
480             integer => sub { Math::BigNum->new_uint($_[0]) },
481             float => sub { Math::BigNum->new($_[0], 10) },
482             binary => sub {
483             my ($const) = @_;
484             my $prefix = substr($const, 0, 2);
485             $prefix eq '0x' ? Math::BigNum->new(substr($const, 2), 16)
486             : $prefix eq '0b' ? Math::BigNum->new(substr($const, 2), 2)
487             : Math::BigNum->new(substr($const, 1), 8);
488             },
489             ;
490              
491             # Export 'Inf' and 'NaN' as constants
492             no strict 'refs';
493              
494             my $inf_sub = $caller . '::' . 'Inf';
495             if (!defined &$inf_sub) {
496             my $inf = inf();
497             *$inf_sub = sub () { $inf };
498             }
499              
500             my $nan_sub = $caller . '::' . 'NaN';
501             if (!defined &$nan_sub) {
502             my $nan = nan();
503             *$nan_sub = sub () { $nan };
504             }
505             }
506             elsif (exists $constants{$name}) {
507             no strict 'refs';
508             my $caller_sub = $caller . '::' . $name;
509             if (!defined &$caller_sub) {
510             my $sub = $constants{$name};
511             my $value = Math::BigNum->$sub;
512             *$caller_sub = sub() { $value }
513             }
514             }
515             elsif (exists $functions{$name}) {
516             no strict 'refs';
517             my $caller_sub = $caller . '::' . $name;
518             if (!defined &$caller_sub) {
519             *$caller_sub = $functions{$name};
520             }
521             }
522             elsif ($name eq ':all') {
523             push @_, keys(%constants), keys(%functions);
524             }
525             elsif ($name eq 'PREC') {
526             my $prec = CORE::int(shift(@_));
527             if ($prec < 2 or $prec > MAX_UI) {
528             die "invalid value for <>: must be between 2 and ", MAX_UI;
529             }
530             $Math::BigNum::PREC = $prec;
531             }
532             else {
533             die "unknown import: <<$name>>";
534             }
535             }
536             return;
537             }
538              
539             sub unimport {
540             overload::remove_constant('binary', '', 'float', '', 'integer');
541             }
542             }
543              
544             # Converts a string representing a floating-point number into a rational representation
545             # Example: "1.234" is converted into "1234/1000"
546             # TODO: find a better solution (maybe)
547             # This solution is very slow for literals with absolute big exponents, such as: "1e-10000000"
548             sub _str2rat {
549             my $str = lc($_[0] || "0");
550              
551             my $sign = substr($str, 0, 1);
552             if ($sign eq '-') {
553             substr($str, 0, 1, '');
554             $sign = '-';
555             }
556             else {
557             substr($str, 0, 1, '') if ($sign eq '+');
558             $sign = '';
559             }
560              
561             my $i;
562             if (($i = index($str, 'e')) != -1) {
563              
564             my $exp = substr($str, $i + 1);
565              
566             # Handle specially numbers with very big exponents
567             # (it's not a very good solution, but I hope it's only temporarily)
568             if (CORE::abs($exp) >= 1000000) {
569             my $mpfr = Math::MPFR::Rmpfr_init2($PREC);
570             Math::MPFR::Rmpfr_set_str($mpfr, "$sign$str", 10, $ROUND);
571             my $mpq = Math::GMPq::Rmpq_init();
572             Math::MPFR::Rmpfr_get_q($mpq, $mpfr);
573             return Math::GMPq::Rmpq_get_str($mpq, 10);
574             }
575              
576             my ($before, $after) = split(/\./, substr($str, 0, $i));
577              
578             if (!defined($after)) { # return faster for numbers like "13e2"
579             if ($exp >= 0) {
580             return ("$sign$before" . ('0' x $exp));
581             }
582             else {
583             $after = '';
584             }
585             }
586              
587             my $numerator = "$before$after";
588             my $denominator = "1";
589              
590             if ($exp < 1) {
591             $denominator .= '0' x (CORE::abs($exp) + CORE::length($after));
592             }
593             else {
594             my $diff = ($exp - CORE::length($after));
595             if ($diff >= 0) {
596             $numerator .= '0' x $diff;
597             }
598             else {
599             my $s = "$before$after";
600             substr($s, $exp + CORE::length($before), 0, '.');
601             return _str2rat("$sign$s");
602             }
603             }
604              
605             "$sign$numerator/$denominator";
606             }
607             elsif (($i = index($str, '.')) != -1) {
608             my ($before, $after) = (substr($str, 0, $i), substr($str, $i + 1));
609             if ($after =~ tr/0// == CORE::length($after)) {
610             return "$sign$before";
611             }
612             $sign . ("$before$after/1" =~ s/^0+//r) . ('0' x CORE::length($after));
613             }
614             else {
615             "$sign$str";
616             }
617             }
618              
619             # Converts a string into an mpfr object
620             sub _str2mpfr {
621             my $r = Math::MPFR::Rmpfr_init2($PREC);
622              
623             if (CORE::int($_[0]) eq $_[0] and $_[0] >= MIN_SI and $_[0] <= MAX_UI) {
624             $_[0] >= 0
625             ? Math::MPFR::Rmpfr_set_ui($r, $_[0], $ROUND)
626             : Math::MPFR::Rmpfr_set_si($r, $_[0], $ROUND);
627             }
628             else {
629             Math::MPFR::Rmpfr_set_str($r, $_[0], 10, $ROUND) && return;
630             }
631              
632             $r;
633             }
634              
635             # Converts a string into an mpq object
636             sub _str2mpq {
637             my $r = Math::GMPq::Rmpq_init();
638              
639             $_[0] || do {
640             Math::GMPq::Rmpq_set($r, $ZERO);
641             return $r;
642             };
643              
644             # Performance improvement for Perl integers
645             if (CORE::int($_[0]) eq $_[0] and $_[0] >= MIN_SI and $_[0] <= MAX_UI) {
646             if ($_[0] >= 0) {
647             Math::GMPq::Rmpq_set_ui($r, $_[0], 1);
648             }
649             else {
650             Math::GMPq::Rmpq_set_si($r, $_[0], 1);
651             }
652             }
653              
654             # Otherwise, it's a string or a float (this is slightly slower)
655             else {
656             my $rat = $_[0] =~ tr/.Ee// ? _str2rat($_[0] =~ tr/_//dr) : ($_[0] =~ tr/_+//dr);
657             if ($rat !~ m{^\s*[-+]?[0-9]+(?>\s*/\s*[-+]?[1-9]+[0-9]*)?\s*\z}) {
658             return;
659             }
660             Math::GMPq::Rmpq_set_str($r, $rat, 10);
661             Math::GMPq::Rmpq_canonicalize($r) if (index($rat, '/') != -1);
662             }
663              
664             $r;
665             }
666              
667             # Converts a string into an mpz object
668             sub _str2mpz {
669             (CORE::int($_[0]) eq $_[0] and $_[0] <= MAX_UI and $_[0] >= MIN_SI)
670             ? (
671             ($_[0] >= 0)
672             ? Math::GMPz::Rmpz_init_set_ui($_[0])
673             : Math::GMPz::Rmpz_init_set_si($_[0])
674             )
675             : eval { Math::GMPz::Rmpz_init_set_str($_[0], 10) };
676             }
677              
678             # Converts a BigNum object to mpfr
679             sub _big2mpfr {
680              
681             $PREC = CORE::int($PREC) if ref($PREC);
682              
683             my $r = Math::MPFR::Rmpfr_init2($PREC);
684             Math::MPFR::Rmpfr_set_q($r, ${$_[0]}, $ROUND);
685             $r;
686             }
687              
688             # Converts a BigNum object to mpz
689             sub _big2mpz {
690             my $z = Math::GMPz::Rmpz_init();
691             Math::GMPz::Rmpz_set_q($z, ${$_[0]});
692             $z;
693             }
694              
695             # Converts an integer BigNum object to mpz
696             sub _int2mpz {
697             my $z = Math::GMPz::Rmpz_init();
698             Math::GMPq::Rmpq_numref($z, ${$_[0]});
699             $z;
700             }
701              
702             # Converts an mpfr object to BigNum
703             sub _mpfr2big {
704              
705             if (!Math::MPFR::Rmpfr_number_p($_[0])) {
706              
707             if (Math::MPFR::Rmpfr_inf_p($_[0])) {
708             if (Math::MPFR::Rmpfr_sgn($_[0]) > 0) {
709             return inf();
710             }
711             else {
712             return ninf();
713             }
714             }
715              
716             if (Math::MPFR::Rmpfr_nan_p($_[0])) {
717             return nan();
718             }
719             }
720              
721             my $r = Math::GMPq::Rmpq_init();
722             Math::MPFR::Rmpfr_get_q($r, $_[0]);
723             bless \$r, __PACKAGE__;
724             }
725              
726             # Converts an mpfr object to mpq and puts it in $x
727             sub _mpfr2x {
728              
729             if (!Math::MPFR::Rmpfr_number_p($_[1])) {
730              
731             if (Math::MPFR::Rmpfr_inf_p($_[1])) {
732             if (Math::MPFR::Rmpfr_sgn($_[1]) > 0) {
733             return $_[0]->binf;
734             }
735             else {
736             return $_[0]->bninf;
737             }
738             }
739              
740             if (Math::MPFR::Rmpfr_nan_p($_[1])) {
741             return $_[0]->bnan;
742             }
743             }
744              
745             Math::MPFR::Rmpfr_get_q(${$_[0]}, $_[1]);
746             $_[0];
747             }
748              
749             # Converts an mpz object to BigNum
750             sub _mpz2big {
751             my $r = Math::GMPq::Rmpq_init();
752             Math::GMPq::Rmpq_set_z($r, $_[0]);
753             bless \$r, __PACKAGE__;
754             }
755              
756             *_big2inf = \&Math::BigNum::Inf::_big2inf;
757             *_big2ninf = \&Math::BigNum::Inf::_big2ninf;
758              
759             #*_big2cplx = \&Math::BigNum::Complex::_big2cplx;
760              
761             =head1 INITIALIZATION / CONSTANTS
762              
763             This section includes methods for creating new B objects
764             and some useful mathematical constants.
765              
766             =cut
767              
768             =head2 new
769              
770             BigNum->new(Scalar) # => BigNum
771             BigNum->new(Scalar, Scalar) # => BigNum
772              
773             Returns a new BigNum object with the value specified in the first argument,
774             which can be a Perl numerical value, a string representing a number in a
775             rational form, such as C<"1/2">, a string holding a floating-point number,
776             such as C<"0.5">, or a string holding an integer, such as C<"255">.
777              
778             The second argument specifies the base of the number, which can range from 2
779             to 36 inclusive and defaults to 10.
780              
781             For setting an hexadecimal number, we can say:
782              
783             my $x = Math::BigNum->new("deadbeef", 16);
784              
785             B no prefix, such as C<"0x"> or C<"0b">, is allowed as part of the number.
786              
787             =cut
788              
789             sub new {
790             my ($class, $num, $base) = @_;
791              
792             my $ref = ref($num);
793              
794             # Be forgetful about undefined values or empty strings
795             if ($ref eq '' and !$num) {
796             return zero();
797             }
798              
799             # Special string values
800             elsif (!defined($base) and $ref eq '') {
801             my $lc = lc($num);
802             if ($lc eq 'inf' or $lc eq '+inf') {
803             return inf();
804             }
805             elsif ($lc eq '-inf') {
806             return ninf();
807             }
808             elsif ($lc eq 'nan') {
809             return nan();
810             }
811             }
812              
813             # Special objects
814             elsif ( $ref eq 'Math::BigNum'
815             or $ref eq 'Math::BigNum::Inf'
816             or $ref eq 'Math::BigNum::Nan') {
817             return $num->copy;
818             }
819              
820             # Special values as Big{Int,Float,Rat}
821             elsif ( $ref eq 'Math::BigInt'
822             or $ref eq 'Math::BigFloat'
823             or $ref eq 'Math::BigRat') {
824             if ($num->is_nan) {
825             return nan();
826             }
827             elsif ($num->is_inf('-')) {
828             return ninf();
829             }
830             elsif ($num->is_inf('+')) {
831             return inf();
832             }
833             }
834              
835             # GMPz
836             elsif ($ref eq 'Math::GMPz') {
837             return _mpz2big($num);
838             }
839              
840             # MPFR
841             elsif ($ref eq 'Math::MPFR') {
842             return _mpfr2big($num);
843             }
844              
845             # Plain scalar
846             if ($ref eq '' and (!defined($base) or $base == 10)) { # it's a base 10 scalar
847             return bless \(_str2mpq($num) // return nan()), $class; # so we can return faster
848             }
849              
850             # Create a new GMPq object
851             my $r = Math::GMPq::Rmpq_init();
852              
853             # BigInt
854             if ($ref eq 'Math::BigInt') {
855             Math::GMPq::Rmpq_set_str($r, $num->bstr, 10);
856             }
857              
858             # BigFloat
859             elsif ($ref eq 'Math::BigFloat') {
860             my $rat = _str2rat($num->bstr);
861             Math::GMPq::Rmpq_set_str($r, $rat, 10);
862             Math::GMPq::Rmpq_canonicalize($r) if (index($rat, '/') != -1);
863             }
864              
865             # BigRat
866             elsif ($ref eq 'Math::BigRat') {
867             Math::GMPq::Rmpq_set_str($r, $num->bstr, 10);
868             }
869              
870             # GMPq
871             elsif ($ref eq 'Math::GMPq') {
872             Math::GMPq::Rmpq_set($r, $num);
873             }
874              
875             # Number with base
876             elsif (defined($base) and $ref eq '') {
877              
878             if ($base < 2 or $base > 36) {
879             require Carp;
880             Carp::croak("base must be between 2 and 36, got $base");
881             }
882              
883             Math::GMPq::Rmpq_set_str($r, $num, $base);
884             Math::GMPq::Rmpq_canonicalize($r) if (index($num, '/') != -1);
885             }
886              
887             # Other reference (which may support stringification)
888             else {
889             Math::GMPq::Rmpq_set($r, _str2mpq("$num") // return nan());
890             }
891              
892             # Return a blessed BigNum object
893             bless \$r, $class;
894             }
895              
896             =head2 new_int
897              
898             BigNum->new_int(Scalar) # => BigNum
899              
900             A faster version of the method C for setting a I native integer.
901              
902             Example:
903              
904             my $x = Math::BigNum->new_int(-42);
905              
906             =cut
907              
908             sub new_int {
909             my $r = Math::GMPq::Rmpq_init();
910             Math::GMPq::Rmpq_set_si($r, $_[1], 1);
911             bless \$r, __PACKAGE__;
912             }
913              
914             =head2 new_uint
915              
916             BigNum->new_uint(Scalar) # => BigNum
917              
918             A faster version of the method C for setting an I native integer.
919              
920             Example:
921              
922             my $x = Math::BigNum->new_uint(42);
923              
924             =cut
925              
926             sub new_uint {
927             my $r = Math::GMPq::Rmpq_init();
928             Math::GMPq::Rmpq_set_ui($r, $_[1], 1);
929             bless \$r, __PACKAGE__;
930             }
931              
932             #
933             ## Constants
934             #
935              
936             =head2 nan
937              
938             BigNum->nan # => Nan
939              
940             Returns a new Nan object.
941              
942             =cut
943              
944             BEGIN { *nan = \&Math::BigNum::Nan::nan }
945              
946             =head2 inf
947              
948             BigNum->inf # => Inf
949              
950             Returns a new Inf object to represent positive Infinity.
951              
952             =cut
953              
954             BEGIN { *inf = \&Math::BigNum::Inf::inf }
955              
956             =head2 ninf
957              
958             BigNum->ninf # => -Inf
959              
960             Returns an Inf object to represent negative Infinity.
961              
962             =cut
963              
964             BEGIN { *ninf = \&Math::BigNum::Inf::ninf }
965              
966             =head2 one
967              
968             BigNum->one # => BigNum
969              
970             Returns a BigNum object containing the value C<1>.
971              
972             =cut
973              
974             sub one {
975             my $r = Math::GMPq::Rmpq_init();
976             Math::GMPq::Rmpq_set($r, $ONE);
977             bless \$r, __PACKAGE__;
978             }
979              
980             =head2 zero
981              
982             BigNum->zero # => BigNum
983              
984             Returns a BigNum object containing the value C<0>.
985              
986             =cut
987              
988             sub zero {
989             my $r = Math::GMPq::Rmpq_init();
990             Math::GMPq::Rmpq_set($r, $ZERO);
991             bless \$r, __PACKAGE__;
992             }
993              
994             =head2 mone
995              
996             BigNum->mone # => BigNum
997              
998             Returns a BigNum object containing the value C<-1>.
999              
1000             =cut
1001              
1002             sub mone {
1003             my $r = Math::GMPq::Rmpq_init();
1004             Math::GMPq::Rmpq_set($r, $MONE);
1005             bless \$r, __PACKAGE__;
1006             }
1007              
1008             =head2 bzero
1009              
1010             $x->bzero # => BigNum
1011              
1012             Changes C in-place to hold the value 0.
1013              
1014             =cut
1015              
1016             sub bzero {
1017             my ($x) = @_;
1018             Math::GMPq::Rmpq_set($$x, $ZERO);
1019             if (ref($x) ne __PACKAGE__) {
1020             bless $x, __PACKAGE__;
1021             }
1022             $x;
1023             }
1024              
1025             =head2 bone
1026              
1027             $x->bone # => BigNum
1028              
1029             Changes C in-place to hold the value +1.
1030              
1031             =cut
1032              
1033             sub bone {
1034             my ($x) = @_;
1035             Math::GMPq::Rmpq_set($$x, $ONE);
1036             if (ref($x) ne __PACKAGE__) {
1037             bless $x, __PACKAGE__;
1038             }
1039             $x;
1040             }
1041              
1042             =head2 bmone
1043              
1044             $x->bmone # => BigNum
1045              
1046             Changes C in-place to hold the value -1.
1047              
1048             =cut
1049              
1050             sub bmone {
1051             my ($x) = @_;
1052             Math::GMPq::Rmpq_set($$x, $MONE);
1053             if (ref($x) ne __PACKAGE__) {
1054             bless $x, __PACKAGE__;
1055             }
1056             $x;
1057             }
1058              
1059             =head2 binf
1060              
1061             $x->binf # => Inf
1062              
1063             Changes C in-place to positive Infinity.
1064              
1065             =cut
1066              
1067             *binf = \&Math::BigNum::Inf::binf;
1068              
1069             =head2 bninf
1070              
1071             $x->bninf # => -Inf
1072              
1073             Changes C in-place to negative Infinity.
1074              
1075             =cut
1076              
1077             *bninf = \&Math::BigNum::Inf::bninf;
1078              
1079             =head2 bnan
1080              
1081             $x->bnan # => Nan
1082              
1083             Changes C in-place to the special Not-a-Number value.
1084              
1085             =cut
1086              
1087             *bnan = \&Math::BigNum::Nan::bnan;
1088              
1089             =head2 pi
1090              
1091             BigNum->pi # => BigNum
1092              
1093             Returns the number PI, which is C<3.1415...>.
1094              
1095             =cut
1096              
1097             sub pi {
1098             my $pi = Math::MPFR::Rmpfr_init2($PREC);
1099             Math::MPFR::Rmpfr_const_pi($pi, $ROUND);
1100             _mpfr2big($pi);
1101             }
1102              
1103             =head2 tau
1104              
1105             BigNum->tau # => BigNum
1106              
1107             Returns the number TAU, which is C<2*PI>.
1108              
1109             =cut
1110              
1111             sub tau {
1112             my $tau = Math::MPFR::Rmpfr_init2($PREC);
1113             Math::MPFR::Rmpfr_const_pi($tau, $ROUND);
1114             Math::MPFR::Rmpfr_mul_ui($tau, $tau, 2, $ROUND);
1115             _mpfr2big($tau);
1116             }
1117              
1118             =head2 ln2
1119              
1120             BigNum->ln2 # => BigNum
1121              
1122             Returns the natural logarithm of C<2>.
1123              
1124             =cut
1125              
1126             sub ln2 {
1127             my $ln2 = Math::MPFR::Rmpfr_init2($PREC);
1128             Math::MPFR::Rmpfr_const_log2($ln2, $ROUND);
1129             _mpfr2big($ln2);
1130             }
1131              
1132             =head2 Y
1133              
1134             BigNum->Y # => BigNum
1135              
1136             Returns the Euler-Mascheroni constant, which is C<0.57721...>.
1137              
1138             =cut
1139              
1140             sub Y {
1141             my $euler = Math::MPFR::Rmpfr_init2($PREC);
1142             Math::MPFR::Rmpfr_const_euler($euler, $ROUND);
1143             _mpfr2big($euler);
1144             }
1145              
1146             =head2 G
1147              
1148             BigNum->G # => BigNum
1149              
1150             Returns the value of Catalan's constant, also known
1151             as Beta(2) or G, and starts as: C<0.91596...>.
1152              
1153             =cut
1154              
1155             sub G {
1156             my $catalan = Math::MPFR::Rmpfr_init2($PREC);
1157             Math::MPFR::Rmpfr_const_catalan($catalan, $ROUND);
1158             _mpfr2big($catalan);
1159             }
1160              
1161             =head2 e
1162              
1163             BigNum->e # => BigNum
1164              
1165             Returns the e mathematical constant, which is C<2.718...>.
1166              
1167             =cut
1168              
1169             sub e {
1170             state $one_f = (Math::MPFR::Rmpfr_init_set_ui_nobless(1, $ROUND))[0];
1171             my $e = Math::MPFR::Rmpfr_init2($PREC);
1172             Math::MPFR::Rmpfr_exp($e, $one_f, $ROUND);
1173             _mpfr2big($e);
1174             }
1175              
1176             =head2 phi
1177              
1178             BigNum->phi # => BigNum
1179              
1180             Returns the value of the golden ratio, which is C<1.61803...>.
1181              
1182             =cut
1183              
1184             sub phi {
1185             state $five4_f = (Math::MPFR::Rmpfr_init_set_str_nobless("1.25", 10, $ROUND))[0];
1186             state $half_f = (Math::MPFR::Rmpfr_init_set_str_nobless("0.5", 10, $ROUND))[0];
1187              
1188             my $phi = Math::MPFR::Rmpfr_init2($PREC);
1189             Math::MPFR::Rmpfr_sqrt($phi, $five4_f, $ROUND);
1190             Math::MPFR::Rmpfr_add($phi, $phi, $half_f, $ROUND);
1191              
1192             _mpfr2big($phi);
1193             }
1194              
1195             ############################ RATIONAL OPERATIONS ############################
1196              
1197             =head1 RATIONAL OPERATIONS
1198              
1199             All operations in this section are done rationally, which means that the
1200             returned results are 100% exact (unless otherwise stated in some special cases).
1201              
1202             =cut
1203              
1204             =head2 add
1205              
1206             $x->add(BigNum) # => BigNum
1207             $x->add(Scalar) # => BigNum
1208              
1209             BigNum + BigNum # => BigNum
1210             BigNum + Scalar # => BigNum
1211             Scalar + BigNum # => BigNum
1212              
1213             Adds C to C and returns the result.
1214              
1215             =cut
1216              
1217             Class::Multimethods::multimethod add => qw(Math::BigNum Math::BigNum) => sub {
1218             my ($x, $y) = @_;
1219             my $r = Math::GMPq::Rmpq_init();
1220             Math::GMPq::Rmpq_add($r, $$x, $$y);
1221             bless \$r, __PACKAGE__;
1222             };
1223              
1224             Class::Multimethods::multimethod add => qw(Math::BigNum $) => sub {
1225             my ($x, $y) = @_;
1226             my $r = _str2mpq($y) // return Math::BigNum->new($y)->badd($x);
1227             Math::GMPq::Rmpq_add($r, $r, $$x);
1228             bless \$r, __PACKAGE__;
1229             };
1230              
1231             =for comment
1232             Class::Multimethods::multimethod add => qw(Math::BigNum Math::BigNum::Complex) => sub {
1233             Math::BigNum::Complex->new($_[0])->add($_[1]);
1234             };
1235             =cut
1236              
1237             Class::Multimethods::multimethod add => qw(Math::BigNum *) => sub {
1238             Math::BigNum->new($_[1])->badd($_[0]);
1239             };
1240              
1241             Class::Multimethods::multimethod add => qw(Math::BigNum Math::BigNum::Inf) => sub { $_[1]->copy };
1242             Class::Multimethods::multimethod add => qw(Math::BigNum Math::BigNum::Nan) => \&nan;
1243              
1244             =head2 badd
1245              
1246             $x->badd(BigNum) # => BigNum
1247             $x->badd(Scalar) # => BigNum
1248              
1249             BigNum += BigNum # => BigNum
1250             BigNum += Scalar # => BigNum
1251              
1252             Adds C to C, changing C in-place.
1253              
1254             =cut
1255              
1256             Class::Multimethods::multimethod badd => qw(Math::BigNum Math::BigNum) => sub {
1257             my ($x, $y) = @_;
1258             Math::GMPq::Rmpq_add($$x, $$x, $$y);
1259             $x;
1260             };
1261              
1262             Class::Multimethods::multimethod badd => qw(Math::BigNum $) => sub {
1263             my ($x, $y) = @_;
1264             Math::GMPq::Rmpq_add($$x, $$x, _str2mpq($y) // return $x->badd(Math::BigNum->new($y)));
1265             $x;
1266             };
1267              
1268             Class::Multimethods::multimethod badd => qw(Math::BigNum *) => sub {
1269             $_[0]->badd(Math::BigNum->new($_[1]));
1270             };
1271              
1272             Class::Multimethods::multimethod badd => qw(Math::BigNum Math::BigNum::Inf) => \&_big2inf;
1273             Class::Multimethods::multimethod badd => qw(Math::BigNum Math::BigNum::Nan) => \&bnan;
1274              
1275             =head2 sub
1276              
1277             $x->sub(BigNum) # => BigNum
1278             $x->sub(Scalar) # => BigNum
1279              
1280             BigNum - BigNum # => BigNum
1281             BigNum - Scalar # => BigNum
1282             Scalar - BigNum # => BigNum
1283              
1284             Subtracts C from C and returns the result.
1285              
1286             =cut
1287              
1288             Class::Multimethods::multimethod sub => qw(Math::BigNum Math::BigNum) => sub {
1289             my ($x, $y) = @_;
1290             my $r = Math::GMPq::Rmpq_init();
1291             Math::GMPq::Rmpq_sub($r, $$x, $$y);
1292             bless \$r, __PACKAGE__;
1293             };
1294              
1295             Class::Multimethods::multimethod sub => qw(Math::BigNum $) => sub {
1296             my ($x, $y) = @_;
1297             my $r = _str2mpq($y) // return Math::BigNum->new($y)->bneg->badd($x);
1298             Math::GMPq::Rmpq_sub($r, $$x, $r);
1299             bless \$r, __PACKAGE__;
1300             };
1301              
1302             Class::Multimethods::multimethod sub => qw($ Math::BigNum) => sub {
1303             my ($x, $y) = @_;
1304             my $r = _str2mpq($x) // return Math::BigNum->new($x)->bsub($y);
1305             Math::GMPq::Rmpq_sub($r, $r, $$y);
1306             bless \$r, __PACKAGE__;
1307             };
1308              
1309             =for comment
1310             Class::Multimethods::multimethod sub => qw(Math::BigNum Math::BigNum::Complex) => sub {
1311             Math::BigNum::Complex->new($_[0])->sub($_[1]);
1312             };
1313             =cut
1314              
1315             Class::Multimethods::multimethod sub => qw(* Math::BigNum) => sub {
1316             Math::BigNum->new($_[0])->bsub($_[1]);
1317             };
1318              
1319             Class::Multimethods::multimethod sub => qw(Math::BigNum *) => sub {
1320             Math::BigNum->new($_[1])->bneg->badd($_[0]);
1321             };
1322              
1323             Class::Multimethods::multimethod sub => qw(Math::BigNum Math::BigNum::Inf) => sub { $_[1]->neg };
1324             Class::Multimethods::multimethod sub => qw(Math::BigNum Math::BigNum::Nan) => \&nan;
1325              
1326             =head2 bsub
1327              
1328             $x->bsub(BigNum) # => BigNum
1329             $x->bsub(Scalar) # => BigNum
1330              
1331             BigNum -= BigNum # => BigNum
1332             BigNum -= Scalar # => BigNum
1333              
1334             Subtracts C from C by changing C in-place.
1335              
1336             =cut
1337              
1338             Class::Multimethods::multimethod bsub => qw(Math::BigNum Math::BigNum) => sub {
1339             my ($x, $y) = @_;
1340             Math::GMPq::Rmpq_sub($$x, $$x, $$y);
1341             $x;
1342             };
1343              
1344             Class::Multimethods::multimethod bsub => qw(Math::BigNum $) => sub {
1345             my ($x, $y) = @_;
1346             Math::GMPq::Rmpq_sub($$x, $$x, _str2mpq($y) // return $x->bsub(Math::BigNum->new($y)));
1347             $x;
1348             };
1349              
1350             Class::Multimethods::multimethod bsub => qw(Math::BigNum *) => sub {
1351             $_[0]->bsub(Math::BigNum->new($_[1]));
1352             };
1353              
1354             Class::Multimethods::multimethod bsub => qw(Math::BigNum Math::BigNum::Inf) => \&_big2ninf;
1355             Class::Multimethods::multimethod bsub => qw(Math::BigNum Math::BigNum::Nan) => \&bnan;
1356              
1357             =head2 mul
1358              
1359             $x->mul(BigNum) # => BigNum
1360             $x->mul(Scalar) # => BigNum
1361              
1362             BigNum * BigNum # => BigNum
1363             BigNum * Scalar # => BigNum
1364             Scalar * BigNum # => BigNum
1365              
1366             Multiplies C by C and returns the result.
1367              
1368             =cut
1369              
1370             Class::Multimethods::multimethod mul => qw(Math::BigNum Math::BigNum) => sub {
1371             my ($x, $y) = @_;
1372             my $r = Math::GMPq::Rmpq_init();
1373             Math::GMPq::Rmpq_mul($r, $$x, $$y);
1374             bless \$r, __PACKAGE__;
1375             };
1376              
1377             Class::Multimethods::multimethod mul => qw(Math::BigNum $) => sub {
1378             my ($x, $y) = @_;
1379             my $r = _str2mpq($y) // return Math::BigNum->new($y)->bmul($x);
1380             Math::GMPq::Rmpq_mul($r, $$x, $r);
1381             bless \$r, __PACKAGE__;
1382             };
1383              
1384             =for comment
1385             Class::Multimethods::multimethod mul => qw(Math::BigNum Math::BigNum::Complex) => sub {
1386             $_[1]->mul($_[0]);
1387             };
1388             =cut
1389              
1390             Class::Multimethods::multimethod mul => qw(Math::BigNum *) => sub {
1391             Math::BigNum->new($_[1])->bmul($_[0]);
1392             };
1393              
1394             Class::Multimethods::multimethod mul => qw(Math::BigNum Math::BigNum::Inf) => sub {
1395             my $sign = Math::GMPq::Rmpq_sgn(${$_[0]});
1396             $sign < 0 ? $_[1]->neg : $sign > 0 ? $_[1]->copy : nan;
1397             };
1398              
1399             Class::Multimethods::multimethod mul => qw(Math::BigNum Math::BigNum::Nan) => \&nan;
1400              
1401             =head2 bmul
1402              
1403             $x->bmul(BigNum) # => BigNum
1404             $x->bmul(Scalar) # => BigNum
1405              
1406             BigNum *= BigNum # => BigNum
1407             BigNum *= Scalar # => BigNum
1408              
1409             Multiply C by C, changing C in-place.
1410              
1411             =cut
1412              
1413             Class::Multimethods::multimethod bmul => qw(Math::BigNum Math::BigNum) => sub {
1414             my ($x, $y) = @_;
1415             Math::GMPq::Rmpq_mul($$x, $$x, $$y);
1416             $x;
1417             };
1418              
1419             Class::Multimethods::multimethod bmul => qw(Math::BigNum $) => sub {
1420             my ($x, $y) = @_;
1421             Math::GMPq::Rmpq_mul($$x, $$x, _str2mpq($y) // return $x->bmul(Math::BigNum->new($y)));
1422             $x;
1423             };
1424              
1425             Class::Multimethods::multimethod bmul => qw(Math::BigNum *) => sub {
1426             $_[0]->bmul(Math::BigNum->new($_[1]));
1427             };
1428              
1429             Class::Multimethods::multimethod bmul => qw(Math::BigNum Math::BigNum::Inf) => sub {
1430             my ($x) = @_;
1431             my $sign = Math::GMPq::Rmpq_sgn($$x);
1432              
1433             $sign < 0 ? _big2ninf(@_)
1434             : $sign > 0 ? _big2inf(@_)
1435             : $x->bnan;
1436             };
1437              
1438             Class::Multimethods::multimethod bmul => qw(Math::BigNum Math::BigNum::Nan) => \&bnan;
1439              
1440             =head2 div
1441              
1442             $x->div(BigNum) # => BigNum | Inf | Nan
1443             $x->div(Scalar) # => BigNum | Inf | Nan
1444              
1445             BigNum / BigNum # => BigNum | Inf | Nan
1446             BigNum / Scalar # => BigNum | Inf | Nan
1447             Scalar / BigNum # => BigNum | Inf | Nan
1448              
1449             Divides C by C and returns the result. Returns Nan when C and C are 0,
1450             Inf when C is 0 and C is positive, -Inf when C is zero and C is negative.
1451              
1452             =cut
1453              
1454             Class::Multimethods::multimethod div => qw(Math::BigNum Math::BigNum) => sub {
1455             my ($x, $y) = @_;
1456              
1457             Math::GMPq::Rmpq_sgn($$y) || do {
1458             my $sign = Math::GMPq::Rmpq_sgn($$x);
1459             return (!$sign ? nan : $sign > 0 ? inf : ninf);
1460             };
1461              
1462             my $r = Math::GMPq::Rmpq_init();
1463             Math::GMPq::Rmpq_div($r, $$x, $$y);
1464             bless \$r, __PACKAGE__;
1465             };
1466              
1467             Class::Multimethods::multimethod div => qw(Math::BigNum $) => sub {
1468             my ($x, $y) = @_;
1469              
1470             $y || do {
1471             my $sign = Math::GMPq::Rmpq_sgn($$x);
1472             return (!$sign ? nan : $sign > 0 ? inf : ninf);
1473             };
1474              
1475             my $r = _str2mpq($y) // return $x->div(Math::BigNum->new($y));
1476             Math::GMPq::Rmpq_div($r, $$x, $r);
1477             bless \$r, __PACKAGE__;
1478             };
1479              
1480             Class::Multimethods::multimethod div => qw($ Math::BigNum) => sub {
1481             my ($x, $y) = @_;
1482              
1483             Math::GMPq::Rmpq_sgn($$y)
1484             || return (!$x ? nan : $x > 0 ? inf : ninf);
1485              
1486             my $r = _str2mpq($x) // return Math::BigNum->new($x)->bdiv($y);
1487             Math::GMPq::Rmpq_div($r, $r, $$y);
1488             bless \$r, __PACKAGE__;
1489             };
1490              
1491             =for comment
1492             Class::Multimethods::multimethod div => qw(Math::BigNum Math::BigNum::Complex) => sub {
1493             Math::BigNum::Complex->new($_[0])->div($_[1]);
1494             };
1495             =cut
1496              
1497             Class::Multimethods::multimethod div => qw(* Math::BigNum) => sub {
1498             Math::BigNum->new($_[0])->bdiv($_[1]);
1499             };
1500              
1501             Class::Multimethods::multimethod div => qw(Math::BigNum *) => sub {
1502             Math::BigNum->new($_[1])->binv->bmul($_[0]);
1503             };
1504              
1505             Class::Multimethods::multimethod div => qw(Math::BigNum Math::BigNum::Inf) => \&zero;
1506             Class::Multimethods::multimethod div => qw(Math::BigNum Math::BigNum::Nan) => \&nan;
1507              
1508             =head2 bdiv
1509              
1510             $x->bdiv(BigNum) # => BigNum | Nan | Inf
1511             $x->bdiv(Scalar) # => BigNum | Nan | Inf
1512              
1513             BigNum /= BigNum # => BigNum | Nan | Inf
1514             BigNum /= Scalar # => BigNum | Nan | Inf
1515              
1516             Divide C by C, changing C in-place. The return values are the same as for C.
1517              
1518             =cut
1519              
1520             Class::Multimethods::multimethod bdiv => qw(Math::BigNum Math::BigNum) => sub {
1521             my ($x, $y) = @_;
1522              
1523             Math::GMPq::Rmpq_sgn($$y) || do {
1524             my $sign = Math::GMPq::Rmpq_sgn($$x);
1525             return
1526             $sign > 0 ? $x->binf
1527             : $sign < 0 ? $x->bninf
1528             : $x->bnan;
1529             };
1530              
1531             Math::GMPq::Rmpq_div($$x, $$x, $$y);
1532             $x;
1533             };
1534              
1535             Class::Multimethods::multimethod bdiv => qw(Math::BigNum $) => sub {
1536             my ($x, $y) = @_;
1537              
1538             $y || do {
1539             my $sign = Math::GMPq::Rmpq_sgn($$x);
1540             return
1541             $sign > 0 ? $x->binf
1542             : $sign < 0 ? $x->bninf
1543             : $x->bnan;
1544             };
1545              
1546             Math::GMPq::Rmpq_div($$x, $$x, _str2mpq($y) // return $x->bdiv(Math::BigNum->new($y)));
1547             $x;
1548             };
1549              
1550             Class::Multimethods::multimethod bdiv => qw(Math::BigNum *) => sub {
1551             $_[0]->bdiv(Math::BigNum->new($_[1]));
1552             };
1553              
1554             Class::Multimethods::multimethod bdiv => qw(Math::BigNum Math::BigNum::Inf) => \&bzero;
1555             Class::Multimethods::multimethod bdiv => qw(Math::BigNum Math::BigNum::Nan) => \&bnan;
1556              
1557             =head2 mod
1558              
1559             $x->mod(BigNum) # => BigNum | Nan
1560             $x->mod(Scalar) # => BigNum | Nan
1561              
1562             BigNum % BigNum # => BigNum | Nan
1563             BigNum % Scalar # => BigNum | Nan
1564             Scalar % BigNum # => BigNum | Nan
1565              
1566             Remainder of C when is divided by C. Returns Nan when C is zero.
1567              
1568             When C and C are both integers, the returned result is exact.
1569             Otherwise, the result is a floating-point approximation.
1570              
1571             =cut
1572              
1573             Class::Multimethods::multimethod mod => qw(Math::BigNum Math::BigNum) => sub {
1574             my ($x, $y) = @_;
1575              
1576             if (Math::GMPq::Rmpq_integer_p($$x) and Math::GMPq::Rmpq_integer_p($$y)) {
1577              
1578             my $yz = _int2mpz($y);
1579             my $sign_y = Math::GMPz::Rmpz_sgn($yz);
1580             return nan if !$sign_y;
1581              
1582             my $r = _int2mpz($x);
1583             Math::GMPz::Rmpz_mod($r, $r, $yz);
1584             if (!Math::GMPz::Rmpz_sgn($r)) {
1585             return (zero); # return faster
1586             }
1587             elsif ($sign_y < 0) {
1588             Math::GMPz::Rmpz_add($r, $r, $yz);
1589             }
1590             _mpz2big($r);
1591             }
1592             else {
1593             my $r = _big2mpfr($x);
1594             my $yf = _big2mpfr($y);
1595             Math::MPFR::Rmpfr_fmod($r, $r, $yf, $ROUND);
1596             my $sign_r = Math::MPFR::Rmpfr_sgn($r);
1597             if (!$sign_r) {
1598             return (zero); # return faster
1599             }
1600             elsif ($sign_r > 0 xor Math::MPFR::Rmpfr_sgn($yf) > 0) {
1601             Math::MPFR::Rmpfr_add($r, $r, $yf, $ROUND);
1602             }
1603             _mpfr2big($r);
1604             }
1605             };
1606              
1607             Class::Multimethods::multimethod mod => qw(Math::BigNum $) => sub {
1608             my ($x, $y) = @_;
1609              
1610             return nan if ($y == 0);
1611              
1612             if (CORE::int($y) eq $y and $y >= MIN_SI and $y <= MAX_UI and Math::GMPq::Rmpq_integer_p($$x)) {
1613             my $r = _int2mpz($x);
1614             my $neg_y = $y < 0;
1615             $y = CORE::abs($y) if $neg_y;
1616             Math::GMPz::Rmpz_mod_ui($r, $r, $y);
1617             if (!Math::GMPz::Rmpz_sgn($r)) {
1618             return (zero); # return faster
1619             }
1620             elsif ($neg_y) {
1621             Math::GMPz::Rmpz_sub_ui($r, $r, $y);
1622             }
1623             _mpz2big($r);
1624             }
1625             else {
1626             my $yf = _str2mpfr($y) // return $x->mod(Math::BigNum->new($y));
1627             my $r = _big2mpfr($x);
1628             Math::MPFR::Rmpfr_fmod($r, $r, $yf, $ROUND);
1629             my $sign = Math::MPFR::Rmpfr_sgn($r);
1630             if (!$sign) {
1631             return (zero); # return faster
1632             }
1633             elsif ($sign > 0 xor Math::MPFR::Rmpfr_sgn($yf) > 0) {
1634             Math::MPFR::Rmpfr_add($r, $r, $yf, $ROUND);
1635             }
1636             _mpfr2big($r);
1637             }
1638             };
1639              
1640             Class::Multimethods::multimethod mod => qw(* Math::BigNum) => sub {
1641             Math::BigNum->new($_[0])->bmod($_[1]);
1642             };
1643              
1644             Class::Multimethods::multimethod mod => qw(Math::BigNum *) => sub {
1645             $_[0]->mod(Math::BigNum->new($_[1]));
1646             };
1647              
1648             Class::Multimethods::multimethod mod => qw(Math::BigNum Math::BigNum::Inf) => sub {
1649             $_[0]->copy->bmod($_[1]);
1650             };
1651              
1652             Class::Multimethods::multimethod mod => qw(Math::BigNum Math::BigNum::Nan) => \&nan;
1653              
1654             =head2 bmod
1655              
1656             $x->bmod(BigNum) # => BigNum | Nan
1657             $x->bmod(Scalar) # => BigNum | Nan
1658              
1659             BigNum %= BigNum # => BigNum | Nan
1660             BigNum %= Scalar # => BigNum | Nan
1661              
1662             Sets C to the remainder of C when is divided by C. Sets C to Nan when C is zero.
1663              
1664             =cut
1665              
1666             Class::Multimethods::multimethod bmod => qw(Math::BigNum Math::BigNum) => sub {
1667             my ($x, $y) = @_;
1668              
1669             if (Math::GMPq::Rmpq_integer_p($$x) and Math::GMPq::Rmpq_integer_p($$y)) {
1670              
1671             my $yz = _int2mpz($y);
1672             my $sign_y = Math::GMPz::Rmpz_sgn($yz);
1673             return $x->bnan if !$sign_y;
1674              
1675             my $r = _int2mpz($x);
1676             Math::GMPz::Rmpz_mod($r, $r, $yz);
1677             if ($sign_y < 0 and Math::GMPz::Rmpz_sgn($r)) {
1678             Math::GMPz::Rmpz_add($r, $r, $yz);
1679             }
1680             Math::GMPq::Rmpq_set_z($$x, $r);
1681             }
1682             else {
1683             my $r = _big2mpfr($x);
1684             my $yf = _big2mpfr($y);
1685             Math::MPFR::Rmpfr_fmod($r, $r, $yf, $ROUND);
1686             my $sign = Math::MPFR::Rmpfr_sgn($r);
1687             if (!$sign) {
1688             ## ok
1689             }
1690             elsif ($sign > 0 xor Math::MPFR::Rmpfr_sgn($yf) > 0) {
1691             Math::MPFR::Rmpfr_add($r, $r, $yf, $ROUND);
1692             }
1693             _mpfr2x($x, $r);
1694             }
1695              
1696             $x;
1697             };
1698              
1699             Class::Multimethods::multimethod bmod => qw(Math::BigNum $) => sub {
1700             my ($x, $y) = @_;
1701              
1702             return $x->bnan if ($y == 0);
1703              
1704             if (CORE::int($y) eq $y and $y >= MIN_SI and $y <= MAX_UI and Math::GMPq::Rmpq_integer_p($$x)) {
1705             my $r = _int2mpz($x);
1706             my $neg_y = $y < 0;
1707             $y = CORE::abs($y) if $neg_y;
1708             Math::GMPz::Rmpz_mod_ui($r, $r, $y);
1709             if ($neg_y and Math::GMPz::Rmpz_sgn($r)) {
1710             Math::GMPz::Rmpz_sub_ui($r, $r, $y);
1711             }
1712             Math::GMPq::Rmpq_set_z($$x, $r);
1713             }
1714             else {
1715             my $yf = _str2mpfr($y) // return $x->bmod(Math::BigNum->new($y));
1716             my $r = _big2mpfr($x);
1717             Math::MPFR::Rmpfr_fmod($r, $r, $yf, $ROUND);
1718             my $sign_r = Math::MPFR::Rmpfr_sgn($r);
1719             if (!$sign_r) {
1720             ## ok
1721             }
1722             elsif ($sign_r > 0 xor Math::MPFR::Rmpfr_sgn($yf) > 0) {
1723             Math::MPFR::Rmpfr_add($r, $r, $yf, $ROUND);
1724             }
1725             _mpfr2x($x, $r);
1726             }
1727              
1728             $x;
1729             };
1730              
1731             Class::Multimethods::multimethod bmod => qw(Math::BigNum *) => sub {
1732             $_[0]->bmod(Math::BigNum->new($_[1]));
1733             };
1734              
1735             # +x mod +Inf = x
1736             # +x mod -Inf = -Inf
1737             # -x mod +Inf = +Inf
1738             # -x mod -Inf = x
1739             Class::Multimethods::multimethod bmod => qw(Math::BigNum Math::BigNum::Inf) => sub {
1740             my ($x, $y) = @_;
1741             Math::GMPq::Rmpq_sgn($$x) == Math::GMPq::Rmpq_sgn($$y) ? $x : _big2inf($x, $y);
1742             };
1743              
1744             Class::Multimethods::multimethod bmod => qw(Math::BigNum Math::BigNum::Nan) => \&bnan;
1745              
1746             =head2 pow
1747              
1748             $x->pow(BigNum) # => BigNum | Nan
1749             $x->pow(Scalar) # => BigNum | Nan
1750              
1751             BigNum ** BigNum # => BigNum | Nan
1752             BigNum ** Scalar # => BigNum | Nan
1753             Scalar ** BigNum # => BigNum | Nan
1754              
1755             Raises C to power C. Returns Nan when C is negative
1756             and C is not an integer.
1757              
1758             When both C and C are integers, it does integer exponentiation and returns the exact result.
1759              
1760             When only C is an integer, it does rational exponentiation based on the identity: C<(a/b)^n = a^n / b^n>,
1761             which computes the exact result.
1762              
1763             When C and C are rationals, it does floating-point exponentiation, which is, in most cases, equivalent
1764             with: C, in which the returned result may not be exact.
1765              
1766             =cut
1767              
1768             Class::Multimethods::multimethod pow => qw(Math::BigNum Math::BigNum) => sub {
1769             my ($x, $y) = @_;
1770              
1771             # Integer power
1772             if (Math::GMPq::Rmpq_integer_p($$y)) {
1773              
1774             my $q = Math::GMPq::Rmpq_init();
1775             my $pow = Math::GMPq::Rmpq_get_d($$y);
1776              
1777             if (Math::GMPq::Rmpq_integer_p($$x)) {
1778              
1779             my $z = _int2mpz($x);
1780             Math::GMPz::Rmpz_pow_ui($z, $z, CORE::abs($pow));
1781             Math::GMPq::Rmpq_set_z($q, $z);
1782              
1783             if ($pow < 0) {
1784             if (!Math::GMPq::Rmpq_sgn($q)) {
1785             return inf();
1786             }
1787             Math::GMPq::Rmpq_inv($q, $q);
1788             }
1789             }
1790             else {
1791             my $z = Math::GMPz::Rmpz_init();
1792             Math::GMPq::Rmpq_numref($z, $$x);
1793             Math::GMPz::Rmpz_pow_ui($z, $z, CORE::abs($pow));
1794              
1795             Math::GMPq::Rmpq_set_num($q, $z);
1796              
1797             Math::GMPq::Rmpq_denref($z, $$x);
1798             Math::GMPz::Rmpz_pow_ui($z, $z, CORE::abs($pow));
1799              
1800             Math::GMPq::Rmpq_set_den($q, $z);
1801              
1802             Math::GMPq::Rmpq_inv($q, $q) if $pow < 0;
1803             }
1804              
1805             return bless \$q, __PACKAGE__;
1806             }
1807              
1808             # Floating-point exponentiation otherwise
1809             my $r = _big2mpfr($x);
1810             Math::MPFR::Rmpfr_pow($r, $r, _big2mpfr($y), $ROUND);
1811             _mpfr2big($r);
1812             };
1813              
1814             =for comment
1815             Class::Multimethods::multimethod pow => qw(Math::BigNum Math::BigNum::Complex) => sub {
1816             Math::BigNum::Complex->new($_[0])->pow($_[1]);
1817             };
1818             =cut
1819              
1820             Class::Multimethods::multimethod pow => qw(Math::BigNum $) => sub {
1821             my ($x, $pow) = @_;
1822              
1823             # Integer power
1824             if (CORE::int($pow) eq $pow and $pow >= MIN_SI and $pow <= MAX_UI) {
1825              
1826             my $q = Math::GMPq::Rmpq_init();
1827              
1828             if (Math::GMPq::Rmpq_integer_p($$x)) {
1829              
1830             my $z = _int2mpz($x);
1831             Math::GMPz::Rmpz_pow_ui($z, $z, CORE::abs($pow));
1832             Math::GMPq::Rmpq_set_z($q, $z);
1833              
1834             if ($pow < 0) {
1835             if (!Math::GMPq::Rmpq_sgn($q)) {
1836             return inf();
1837             }
1838             Math::GMPq::Rmpq_inv($q, $q);
1839             }
1840             }
1841             else {
1842             my $z = Math::GMPz::Rmpz_init();
1843             Math::GMPq::Rmpq_numref($z, $$x);
1844             Math::GMPz::Rmpz_pow_ui($z, $z, CORE::abs($pow));
1845              
1846             Math::GMPq::Rmpq_set_num($q, $z);
1847              
1848             Math::GMPq::Rmpq_denref($z, $$x);
1849             Math::GMPz::Rmpz_pow_ui($z, $z, CORE::abs($pow));
1850              
1851             Math::GMPq::Rmpq_set_den($q, $z);
1852              
1853             Math::GMPq::Rmpq_inv($q, $q) if $pow < 0;
1854             }
1855              
1856             return bless \$q, __PACKAGE__;
1857             }
1858              
1859             $x->pow(Math::BigNum->new($pow));
1860             };
1861              
1862             Class::Multimethods::multimethod pow => qw(* Math::BigNum) => sub {
1863             Math::BigNum->new($_[0])->bpow($_[1]);
1864             };
1865              
1866             Class::Multimethods::multimethod pow => qw(Math::BigNum *) => sub {
1867             $_[0]->pow(Math::BigNum->new($_[1]));
1868             };
1869              
1870             # 0 ** Inf = 0
1871             # 0 ** -Inf = Inf
1872             # (+/-1) ** (+/-Inf) = 1
1873             # x ** (-Inf) = 0
1874             # x ** Inf = Inf
1875              
1876             Class::Multimethods::multimethod pow => qw(Math::BigNum Math::BigNum::Inf) => sub {
1877             $_[0]->is_zero
1878             ? $_[1]->is_neg
1879             ? inf
1880             : zero
1881             : $_[0]->is_one || $_[0]->is_mone ? one
1882             : $_[1]->is_neg ? zero
1883             : inf;
1884             };
1885              
1886             Class::Multimethods::multimethod pow => qw(Math::BigNum Math::BigNum::Nan) => \&nan;
1887              
1888             =head2 bpow
1889              
1890             $x->bpow(BigNum) # => BigNum | Nan
1891             $x->bpow(Scalar) # => BigNum | Nan
1892              
1893             BigNum **= BigNum # => BigNum | Nan
1894             BigNum **= Scalar # => BigNum | Nan
1895             Scalar **= BigNum # => BigNum | Nan
1896              
1897             Raises C to power C, changing C in-place.
1898              
1899             =cut
1900              
1901             Class::Multimethods::multimethod bpow => qw(Math::BigNum Math::BigNum) => sub {
1902             my ($x, $y) = @_;
1903              
1904             # Integer power
1905             if (Math::GMPq::Rmpq_integer_p($$y)) {
1906              
1907             my $q = $$x;
1908             my $pow = Math::GMPq::Rmpq_get_d($$y);
1909              
1910             if (Math::GMPq::Rmpq_integer_p($q)) {
1911             my $z = Math::GMPz::Rmpz_init();
1912             Math::GMPz::Rmpz_set_q($z, $q);
1913             Math::GMPz::Rmpz_pow_ui($z, $z, CORE::abs($pow));
1914             Math::GMPq::Rmpq_set_z($q, $z);
1915              
1916             if ($pow < 0) {
1917             if (!Math::GMPq::Rmpq_sgn($q)) {
1918             return $x->binf;
1919             }
1920             Math::GMPq::Rmpq_inv($q, $q);
1921             }
1922             }
1923             else {
1924             my $z = Math::GMPz::Rmpz_init();
1925             Math::GMPq::Rmpq_numref($z, $q);
1926             Math::GMPz::Rmpz_pow_ui($z, $z, CORE::abs($pow));
1927              
1928             Math::GMPq::Rmpq_set_num($q, $z);
1929              
1930             Math::GMPq::Rmpq_denref($z, $q);
1931             Math::GMPz::Rmpz_pow_ui($z, $z, CORE::abs($pow));
1932              
1933             Math::GMPq::Rmpq_set_den($q, $z);
1934              
1935             Math::GMPq::Rmpq_inv($q, $q) if $pow < 0;
1936             }
1937              
1938             return $x;
1939             }
1940              
1941             # A floating-point otherwise
1942             my $r = _big2mpfr($x);
1943             Math::MPFR::Rmpfr_pow($r, $r, _big2mpfr($y), $ROUND);
1944             _mpfr2x($x, $r);
1945             };
1946              
1947             Class::Multimethods::multimethod bpow => qw(Math::BigNum $) => sub {
1948             my ($x, $pow) = @_;
1949              
1950             my $pow_is_int = (CORE::int($pow) eq $pow and $pow >= MIN_SI and $pow <= MAX_UI);
1951              
1952             # Integer power
1953             if ($pow_is_int) {
1954              
1955             my $q = $$x;
1956              
1957             if (Math::GMPq::Rmpq_integer_p($q)) {
1958             my $z = Math::GMPz::Rmpz_init();
1959             Math::GMPz::Rmpz_set_q($z, $q);
1960             Math::GMPz::Rmpz_pow_ui($z, $z, CORE::abs($pow));
1961             Math::GMPq::Rmpq_set_z($q, $z);
1962              
1963             if ($pow < 0) {
1964             if (!Math::GMPq::Rmpq_sgn($q)) {
1965             return $x->binf;
1966             }
1967             Math::GMPq::Rmpq_inv($q, $q);
1968             }
1969             }
1970             else {
1971             my $z = Math::GMPz::Rmpz_init();
1972             Math::GMPq::Rmpq_numref($z, $$x);
1973             Math::GMPz::Rmpz_pow_ui($z, $z, CORE::abs($pow));
1974              
1975             Math::GMPq::Rmpq_set_num($q, $z);
1976              
1977             Math::GMPq::Rmpq_denref($z, $$x);
1978             Math::GMPz::Rmpz_pow_ui($z, $z, CORE::abs($pow));
1979              
1980             Math::GMPq::Rmpq_set_den($q, $z);
1981              
1982             Math::GMPq::Rmpq_inv($q, $q) if $pow < 0;
1983             }
1984              
1985             return $x;
1986             }
1987              
1988             # A floating-point otherwise
1989             my $r = _big2mpfr($x);
1990             if ($pow_is_int) {
1991             if ($pow >= 0) {
1992             Math::MPFR::Rmpfr_pow_ui($r, $r, $pow, $ROUND);
1993             }
1994             else {
1995             Math::MPFR::Rmpfr_pow_si($r, $r, $pow, $ROUND);
1996             }
1997             }
1998             else {
1999             Math::MPFR::Rmpfr_pow($r, $r, _str2mpfr($pow) // (return $x->bpow(Math::BigNum->new($pow))), $ROUND);
2000             }
2001              
2002             _mpfr2x($x, $r);
2003             };
2004              
2005             Class::Multimethods::multimethod bpow => qw(Math::BigNum *) => sub {
2006             $_[0]->bpow(Math::BigNum->new($_[1]));
2007             };
2008              
2009             # 0 ** Inf = 0
2010             # 0 ** -Inf = Inf
2011             # (+/-1) ** (+/-Inf) = 1
2012             # x ** (-Inf) = 0
2013             # x ** Inf = Inf
2014              
2015             Class::Multimethods::multimethod bpow => qw(Math::BigNum Math::BigNum::Inf) => sub {
2016             $_[0]->is_zero
2017             ? $_[1]->is_neg
2018             ? $_[0]->binf
2019             : $_[0]->bzero
2020             : $_[0]->is_one || $_[0]->is_mone ? $_[0]->bone
2021             : $_[1]->is_neg ? $_[0]->bzero
2022             : $_[0]->binf;
2023             };
2024              
2025             Class::Multimethods::multimethod bpow => qw(Math::BigNum Math::BigNum::Nan) => \&bnan;
2026              
2027             =head2 inv
2028              
2029             $x->inv # => BigNum | Inf
2030              
2031             Inverse value of C. Return Inf when C is zero. (C<1/x>)
2032              
2033             =cut
2034              
2035             sub inv {
2036             my ($x) = @_;
2037              
2038             # Return Inf when $x is zero.
2039             Math::GMPq::Rmpq_sgn($$x)
2040             || return inf();
2041              
2042             my $r = Math::GMPq::Rmpq_init();
2043             Math::GMPq::Rmpq_inv($r, $$x);
2044             bless \$r, __PACKAGE__;
2045             }
2046              
2047             =head2 binv
2048              
2049             $x->binv # => BigNum | Inf
2050              
2051             Set C to its inverse value. (C<1/x>)
2052              
2053             =cut
2054              
2055             sub binv {
2056             my ($x) = @_;
2057              
2058             # Return Inf when $x is zero.
2059             Math::GMPq::Rmpq_sgn($$x)
2060             || return $x->binf;
2061              
2062             Math::GMPq::Rmpq_inv($$x, $$x);
2063             $x;
2064             }
2065              
2066             =head2 sqr
2067              
2068             $x->sqr # => BigNum
2069              
2070             Raise C to the power of 2 and return the result. (C)
2071              
2072             =cut
2073              
2074             sub sqr {
2075             my ($x) = @_;
2076             my $r = Math::GMPq::Rmpq_init();
2077             Math::GMPq::Rmpq_mul($r, $$x, $$x);
2078             bless \$r, __PACKAGE__;
2079             }
2080              
2081             =head2 bsqr
2082              
2083             $x->bsqr # => BigNum
2084              
2085             Set C to its multiplicative double. (C)
2086              
2087             =cut
2088              
2089             sub bsqr {
2090             my ($x) = @_;
2091             Math::GMPq::Rmpq_mul($$x, $$x, $$x);
2092             $x;
2093             }
2094              
2095             =head2 bernfrac
2096              
2097             $n->bernfrac # => BigNum | Nan
2098              
2099             Returns the nth-Bernoulli number C as an exact fraction, computed with an
2100             improved version of Seidel's algorithm, starting with C.
2101              
2102             For n >= 50, a more efficient algorithm is used, based on Zeta(n).
2103              
2104             For negative values of C, Nan is returned.
2105              
2106             =cut
2107              
2108             sub bernfrac {
2109             my ($n) = @_;
2110              
2111             $n = CORE::int(Math::GMPq::Rmpq_get_d($$n));
2112              
2113             $n == 0 and return one();
2114             $n > 1 and $n % 2 and return zero(); # Bn=0 for odd n>1
2115             $n < 0 and return nan();
2116              
2117             # Use a faster algorithm based on values of the Zeta function.
2118             # B(n) = (-1)^(n/2 + 1) * zeta(n)*2*n! / (2*pi)^n
2119             if ($n >= 50) {
2120              
2121             my $prec = (
2122             $n <= 156
2123             ? CORE::int($n * CORE::log($n) + 1)
2124             : CORE::int($n * CORE::log($n) / CORE::log(2) - 3 * $n) # TODO: optimize for large n (>50_000)
2125             );
2126              
2127             my $f = Math::MPFR::Rmpfr_init2($prec);
2128             Math::MPFR::Rmpfr_zeta_ui($f, $n, $ROUND); # f = zeta(n)
2129              
2130             my $z = Math::GMPz::Rmpz_init();
2131             Math::GMPz::Rmpz_fac_ui($z, $n); # z = n!
2132             Math::GMPz::Rmpz_div_2exp($z, $z, $n - 1); # z = z / 2^(n-1)
2133             Math::MPFR::Rmpfr_mul_z($f, $f, $z, $ROUND); # f = f*z
2134              
2135             my $p = Math::MPFR::Rmpfr_init2($prec);
2136             Math::MPFR::Rmpfr_const_pi($p, $ROUND); # p = PI
2137             Math::MPFR::Rmpfr_pow_ui($p, $p, $n, $ROUND); # p = p^n
2138             Math::MPFR::Rmpfr_div($f, $f, $p, $ROUND); # f = f/p
2139              
2140             Math::GMPz::Rmpz_set_ui($z, 1); # z = 1
2141             Math::GMPz::Rmpz_mul_2exp($z, $z, $n + 1); # z = 2^(n+1)
2142             Math::GMPz::Rmpz_sub_ui($z, $z, 2); # z = z-2
2143              
2144             Math::MPFR::Rmpfr_mul_z($f, $f, $z, $ROUND); # f = f*z
2145             Math::MPFR::Rmpfr_round($f, $f); # f = [f]
2146              
2147             my $q = Math::GMPq::Rmpq_init();
2148             Math::MPFR::Rmpfr_get_q($q, $f); # q = f
2149             Math::GMPq::Rmpq_set_den($q, $z); # q = q/z
2150             Math::GMPq::Rmpq_canonicalize($q); # remove common factors
2151              
2152             Math::GMPq::Rmpq_neg($q, $q) if $n % 4 == 0; # q = -q (iff 4|n)
2153             return bless \$q, __PACKAGE__;
2154             }
2155              
2156             #<<<
2157             my @D = (
2158             Math::GMPz::Rmpz_init_set_ui(0),
2159             Math::GMPz::Rmpz_init_set_ui(1),
2160             map { Math::GMPz::Rmpz_init_set_ui(0) } (1 .. $n/2 - 1)
2161             );
2162             #>>>
2163              
2164             my ($h, $w) = (1, 1);
2165             foreach my $i (0 .. $n - 1) {
2166             if ($w ^= 1) {
2167             Math::GMPz::Rmpz_add($D[$_], $D[$_], $D[$_ - 1]) for (1 .. $h - 1);
2168             }
2169             else {
2170             $w = $h++;
2171             Math::GMPz::Rmpz_add($D[$w], $D[$w], $D[$w + 1]) while --$w;
2172             }
2173             }
2174              
2175             my $den = Math::GMPz::Rmpz_init_set($ONE_Z);
2176             Math::GMPz::Rmpz_mul_2exp($den, $den, $n + 1);
2177             Math::GMPz::Rmpz_sub_ui($den, $den, 2);
2178             Math::GMPz::Rmpz_neg($den, $den) if $n % 4 == 0;
2179              
2180             my $r = Math::GMPq::Rmpq_init();
2181             Math::GMPq::Rmpq_set_num($r, $D[$h - 1]);
2182             Math::GMPq::Rmpq_set_den($r, $den);
2183             Math::GMPq::Rmpq_canonicalize($r);
2184              
2185             bless \$r, __PACKAGE__;
2186             }
2187              
2188             =head2 harmfrac
2189              
2190             $n->harmfrac # => BigNum | Nan
2191              
2192             Returns the nth-Harmonic number C. The harmonic numbers are the sum of
2193             reciprocals of the first C natural numbers: C<1 + 1/2 + 1/3 + ... + 1/n>.
2194              
2195             For values greater than 7000, binary splitting (Fredrik Johansson's elegant formulation) is used.
2196              
2197             =cut
2198              
2199             sub harmfrac {
2200             my ($n) = @_;
2201              
2202             my $ui = CORE::int(Math::GMPq::Rmpq_get_d($$n));
2203              
2204             $ui || return zero();
2205             $ui < 0 and return nan();
2206              
2207             # Use binary splitting for large values of n. (by Fredrik Johansson)
2208             # http://fredrik-j.blogspot.ro/2009/02/how-not-to-compute-harmonic-numbers.html
2209             if ($ui > 7000) {
2210              
2211             my $num = Math::GMPz::Rmpz_init_set_ui(1);
2212              
2213             my $den = Math::GMPz::Rmpz_init();
2214             Math::GMPz::Rmpz_set_q($den, $$n);
2215             Math::GMPz::Rmpz_add_ui($den, $den, 1);
2216              
2217             my $temp = Math::GMPz::Rmpz_init();
2218              
2219             # Inspired by Dana Jacobsen's code from Math::Prime::Util::{PP,GMP}.
2220             # https://metacpan.org/pod/Math::Prime::Util::PP
2221             # https://metacpan.org/pod/Math::Prime::Util::GMP
2222             my $sub;
2223             $sub = sub {
2224             my ($num, $den) = @_;
2225             Math::GMPz::Rmpz_sub($temp, $den, $num);
2226              
2227             if (Math::GMPz::Rmpz_cmp_ui($temp, 1) == 0) {
2228             Math::GMPz::Rmpz_set($den, $num);
2229             Math::GMPz::Rmpz_set_ui($num, 1);
2230             }
2231             elsif (Math::GMPz::Rmpz_cmp_ui($temp, 2) == 0) {
2232             Math::GMPz::Rmpz_set($den, $num);
2233             Math::GMPz::Rmpz_mul_2exp($num, $num, 1);
2234             Math::GMPz::Rmpz_add_ui($num, $num, 1);
2235             Math::GMPz::Rmpz_addmul($den, $den, $den);
2236             }
2237             else {
2238             Math::GMPz::Rmpz_add($temp, $num, $den);
2239             Math::GMPz::Rmpz_tdiv_q_2exp($temp, $temp, 1);
2240             my $q = Math::GMPz::Rmpz_init_set($temp);
2241             my $r = Math::GMPz::Rmpz_init_set($temp);
2242             $sub->($num, $q);
2243             $sub->($r, $den);
2244             Math::GMPz::Rmpz_mul($num, $num, $den);
2245             Math::GMPz::Rmpz_mul($temp, $q, $r);
2246             Math::GMPz::Rmpz_add($num, $num, $temp);
2247             Math::GMPz::Rmpz_mul($den, $den, $q);
2248             }
2249             };
2250              
2251             $sub->($num, $den);
2252              
2253             my $q = Math::GMPq::Rmpq_init();
2254             Math::GMPq::Rmpq_set_num($q, $num);
2255             Math::GMPq::Rmpq_set_den($q, $den);
2256             Math::GMPq::Rmpq_canonicalize($q);
2257              
2258             return bless \$q, __PACKAGE__;
2259             }
2260              
2261             my $num = Math::GMPz::Rmpz_init_set_ui(1);
2262             my $den = Math::GMPz::Rmpz_init_set_ui(1);
2263              
2264             for (my $k = 2 ; $k <= $ui ; ++$k) {
2265             Math::GMPz::Rmpz_mul_ui($num, $num, $k); # num = num * k
2266             Math::GMPz::Rmpz_add($num, $num, $den); # num = num + den
2267             Math::GMPz::Rmpz_mul_ui($den, $den, $k); # den = den * k
2268             }
2269              
2270             my $r = Math::GMPq::Rmpq_init();
2271             Math::GMPq::Rmpq_set_num($r, $num);
2272             Math::GMPq::Rmpq_set_den($r, $den);
2273             Math::GMPq::Rmpq_canonicalize($r);
2274              
2275             bless \$r, __PACKAGE__;
2276             }
2277              
2278             ############################ FLOATING-POINT OPERATIONS ############################
2279              
2280             =head1 FLOATING-POINT OPERATIONS
2281              
2282             All the operations in this section are done with floating-point approximations,
2283             which are, in the end, converted to fraction-approximations.
2284             In some cases, the results are 100% exact, but this is not guaranteed.
2285              
2286             =cut
2287              
2288             =head2 fadd
2289              
2290             $x->fadd(BigNum) # => BigNum
2291             $x->fadd(Scalar) # => BigNum
2292              
2293             Floating-point addition of C and C.
2294              
2295             =cut
2296              
2297             Class::Multimethods::multimethod fadd => qw(Math::BigNum Math::BigNum) => sub {
2298             my ($x, $y) = @_;
2299             $x = _big2mpfr($x);
2300             Math::MPFR::Rmpfr_add_q($x, $x, $$y, $ROUND);
2301             _mpfr2big($x);
2302             };
2303              
2304             Class::Multimethods::multimethod fadd => qw(Math::BigNum $) => sub {
2305             my ($x, $y) = @_;
2306              
2307             my $r = _big2mpfr($x);
2308             if (CORE::int($y) eq $y and $y >= MIN_SI and $y <= MAX_UI) {
2309             $y >= 0
2310             ? Math::MPFR::Rmpfr_add_ui($r, $r, $y, $ROUND)
2311             : Math::MPFR::Rmpfr_add_si($r, $r, $y, $ROUND);
2312             }
2313             else {
2314             Math::MPFR::Rmpfr_add($r, $r, _str2mpfr($y) // (return Math::BigNum->new($y)->bfadd($x)), $ROUND);
2315             }
2316             _mpfr2big($r);
2317             };
2318              
2319             Class::Multimethods::multimethod fadd => qw(Math::BigNum *) => sub {
2320             Math::BigNum->new($_[1])->bfadd($_[0]);
2321             };
2322              
2323             Class::Multimethods::multimethod fadd => qw(Math::BigNum Math::BigNum::Inf) => sub { $_[1] };
2324             Class::Multimethods::multimethod fadd => qw(Math::BigNum Math::BigNum::Nan) => \&nan;
2325              
2326             =head2 bfadd
2327              
2328             $x->bfadd(BigNum) # => BigNum
2329             $x->bfadd(Scalar) # => BigNum
2330              
2331             Floating-point addition of C and C, changing C in-place.
2332              
2333             =cut
2334              
2335             Class::Multimethods::multimethod bfadd => qw(Math::BigNum Math::BigNum) => sub {
2336             my ($x, $y) = @_;
2337             my $r = _big2mpfr($x);
2338             Math::MPFR::Rmpfr_add_q($r, $r, $$y, $ROUND);
2339             _mpfr2x($x, $r);
2340             };
2341              
2342             Class::Multimethods::multimethod bfadd => qw(Math::BigNum $) => sub {
2343             my ($x, $y) = @_;
2344              
2345             my $r = _big2mpfr($x);
2346             if (CORE::int($y) eq $y and $y >= MIN_SI and $y <= MAX_UI) {
2347             $y >= 0
2348             ? Math::MPFR::Rmpfr_add_ui($r, $r, $y, $ROUND)
2349             : Math::MPFR::Rmpfr_add_si($r, $r, $y, $ROUND);
2350             }
2351             else {
2352             Math::MPFR::Rmpfr_add($r, $r, _str2mpfr($y) // (return $x->bfadd(Math::BigNum->new($y))), $ROUND);
2353             }
2354             _mpfr2x($x, $r);
2355             };
2356              
2357             Class::Multimethods::multimethod bfadd => qw(Math::BigNum *) => sub {
2358             $_[0]->bfadd(Math::BigNum->new($_[1]));
2359             };
2360              
2361             Class::Multimethods::multimethod bfadd => qw(Math::BigNum Math::BigNum::Inf) => \&_big2inf;
2362             Class::Multimethods::multimethod bfadd => qw(Math::BigNum Math::BigNum::Nan) => \&bnan;
2363              
2364             =head2 fsub
2365              
2366             $x->fsub(BigNum) # => BigNum
2367             $x->fsub(Scalar) # => BigNum
2368              
2369             Floating-point subtraction of C and C.
2370              
2371             =cut
2372              
2373             Class::Multimethods::multimethod fsub => qw(Math::BigNum Math::BigNum) => sub {
2374             my ($x, $y) = @_;
2375             $x = _big2mpfr($x);
2376             Math::MPFR::Rmpfr_sub_q($x, $x, $$y, $ROUND);
2377             _mpfr2big($x);
2378             };
2379              
2380             Class::Multimethods::multimethod fsub => qw(Math::BigNum $) => sub {
2381             my ($x, $y) = @_;
2382              
2383             my $r = _big2mpfr($x);
2384             if (CORE::int($y) eq $y and $y >= MIN_SI and $y <= MAX_UI) {
2385             $y >= 0
2386             ? Math::MPFR::Rmpfr_sub_ui($r, $r, $y, $ROUND)
2387             : Math::MPFR::Rmpfr_sub_si($r, $r, $y, $ROUND);
2388             }
2389             else {
2390             Math::MPFR::Rmpfr_sub($r, $r, _str2mpfr($y) // (return Math::BigNum->new($y)->bneg->bfadd($x)), $ROUND);
2391             }
2392             _mpfr2big($r);
2393             };
2394              
2395             Class::Multimethods::multimethod fsub => qw(Math::BigNum *) => sub {
2396             Math::BigNum->new($_[1])->bneg->bfadd($_[0]);
2397             };
2398              
2399             Class::Multimethods::multimethod fsub => qw(Math::BigNum Math::BigNum::Inf) => sub { $_[1]->neg };
2400             Class::Multimethods::multimethod fsub => qw(Math::BigNum Math::BigNum::Nan) => \&nan;
2401              
2402             =head2 bfsub
2403              
2404             $x->bfsub(BigNum) # => BigNum
2405             $x->bfsub(Scalar) # => BigNum
2406              
2407             Floating-point subtraction of C and C, changing C in-place.
2408              
2409             =cut
2410              
2411             Class::Multimethods::multimethod bfsub => qw(Math::BigNum Math::BigNum) => sub {
2412             my ($x, $y) = @_;
2413             my $r = _big2mpfr($x);
2414             Math::MPFR::Rmpfr_sub_q($r, $r, $$y, $ROUND);
2415             _mpfr2x($x, $r);
2416             };
2417              
2418             Class::Multimethods::multimethod bfsub => qw(Math::BigNum $) => sub {
2419             my ($x, $y) = @_;
2420              
2421             my $r = _big2mpfr($x);
2422             if (CORE::int($y) eq $y and $y >= MIN_SI and $y <= MAX_UI) {
2423             $y >= 0
2424             ? Math::MPFR::Rmpfr_sub_ui($r, $r, $y, $ROUND)
2425             : Math::MPFR::Rmpfr_sub_si($r, $r, $y, $ROUND);
2426             }
2427             else {
2428             Math::MPFR::Rmpfr_sub($r, $r, _str2mpfr($y) // (return $x->bfsub(Math::BigNum->new($y))), $ROUND);
2429             }
2430             _mpfr2x($x, $r);
2431             };
2432              
2433             Class::Multimethods::multimethod bfsub => qw(Math::BigNum *) => sub {
2434             $_[0]->bfsub(Math::BigNum->new($_[1]));
2435             };
2436              
2437             Class::Multimethods::multimethod bfsub => qw(Math::BigNum Math::BigNum::Inf) => \&_big2ninf;
2438             Class::Multimethods::multimethod bfsub => qw(Math::BigNum Math::BigNum::Nan) => \&bnan;
2439              
2440             =head2 fmul
2441              
2442             $x->fmul(BigNum) # => BigNum
2443             $x->fmul(Scalar) # => BigNum
2444              
2445             Floating-point multiplication of C by C.
2446              
2447             =cut
2448              
2449             Class::Multimethods::multimethod fmul => qw(Math::BigNum Math::BigNum) => sub {
2450             my ($x, $y) = @_;
2451             $x = _big2mpfr($x);
2452             Math::MPFR::Rmpfr_mul_q($x, $x, $$y, $ROUND);
2453             _mpfr2big($x);
2454             };
2455              
2456             Class::Multimethods::multimethod fmul => qw(Math::BigNum $) => sub {
2457             my ($x, $y) = @_;
2458              
2459             my $r = _big2mpfr($x);
2460             if (CORE::int($y) eq $y and $y >= MIN_SI and $y <= MAX_UI) {
2461             $y >= 0
2462             ? Math::MPFR::Rmpfr_mul_ui($r, $r, $y, $ROUND)
2463             : Math::MPFR::Rmpfr_mul_si($r, $r, $y, $ROUND);
2464             }
2465             else {
2466             Math::MPFR::Rmpfr_mul($r, $r, _str2mpfr($y) // (return Math::BigNum->new($y)->bfmul($x)), $ROUND);
2467             }
2468             _mpfr2big($r);
2469             };
2470              
2471             Class::Multimethods::multimethod fmul => qw(Math::BigNum *) => sub {
2472             Math::BigNum->new($_[1])->bfmul($_[0]);
2473             };
2474              
2475             Class::Multimethods::multimethod fmul => qw(Math::BigNum Math::BigNum::Inf) => sub {
2476             my $sign = Math::GMPq::Rmpq_sgn(${$_[0]});
2477             $sign < 0 ? $_[1]->neg : $sign > 0 ? $_[1]->copy : nan;
2478             };
2479              
2480             Class::Multimethods::multimethod fmul => qw(Math::BigNum Math::BigNum::Nan) => \&nan;
2481              
2482             =head2 bfmul
2483              
2484             $x->bfmul(BigNum) # => BigNum
2485             $x->bfmul(Scalar) # => BigNum
2486              
2487             Floating-point multiplication of C by C, changing C in-place.
2488              
2489             =cut
2490              
2491             Class::Multimethods::multimethod bfmul => qw(Math::BigNum Math::BigNum) => sub {
2492             my ($x, $y) = @_;
2493             my $r = _big2mpfr($x);
2494             Math::MPFR::Rmpfr_mul_q($r, $r, $$y, $ROUND);
2495             _mpfr2x($x, $r);
2496             };
2497              
2498             Class::Multimethods::multimethod bfmul => qw(Math::BigNum $) => sub {
2499             my ($x, $y) = @_;
2500              
2501             my $r = _big2mpfr($x);
2502             if (CORE::int($y) eq $y and $y >= MIN_SI and $y <= MAX_UI) {
2503             $y >= 0
2504             ? Math::MPFR::Rmpfr_mul_ui($r, $r, $y, $ROUND)
2505             : Math::MPFR::Rmpfr_mul_si($r, $r, $y, $ROUND);
2506             }
2507             else {
2508             Math::MPFR::Rmpfr_mul($r, $r, _str2mpfr($y) // (return $x->bfmul(Math::BigNum->new($y))), $ROUND);
2509             }
2510             _mpfr2x($x, $r);
2511             };
2512              
2513             Class::Multimethods::multimethod bfmul => qw(Math::BigNum *) => sub {
2514             $_[0]->bfmul(Math::BigNum->new($_[1]));
2515             };
2516              
2517             Class::Multimethods::multimethod bfmul => qw(Math::BigNum Math::BigNum::Inf) => sub {
2518             my ($x) = @_;
2519             my $sign = Math::GMPq::Rmpq_sgn($$x);
2520             $sign < 0 ? _big2ninf(@_) : $sign > 0 ? _big2inf(@_) : $x->bnan;
2521             };
2522              
2523             Class::Multimethods::multimethod bfmul => qw(Math::BigNum Math::BigNum::Nan) => \&bnan;
2524              
2525             =head2 fdiv
2526              
2527             $x->fdiv(BigNum) # => BigNum | Nan | Inf
2528             $x->fdiv(Scalar) # => BigNum | Nan | Inf
2529              
2530             Floating-point division of C by C.
2531              
2532             =cut
2533              
2534             Class::Multimethods::multimethod fdiv => qw(Math::BigNum Math::BigNum) => sub {
2535             my ($x, $y) = @_;
2536             $x = _big2mpfr($x);
2537             Math::MPFR::Rmpfr_div_q($x, $x, $$y, $ROUND);
2538             _mpfr2big($x);
2539             };
2540              
2541             Class::Multimethods::multimethod fdiv => qw(Math::BigNum $) => sub {
2542             my ($x, $y) = @_;
2543              
2544             my $r = _big2mpfr($x);
2545             if (CORE::int($y) eq $y and $y >= MIN_SI and $y <= MAX_UI) {
2546             $y >= 0
2547             ? Math::MPFR::Rmpfr_div_ui($r, $r, $y, $ROUND)
2548             : Math::MPFR::Rmpfr_div_si($r, $r, $y, $ROUND);
2549             }
2550             else {
2551             Math::MPFR::Rmpfr_div($r, $r, _str2mpfr($y) // (return Math::BigNum->new($y)->bfdiv($x)->binv), $ROUND);
2552             }
2553             _mpfr2big($r);
2554             };
2555              
2556             Class::Multimethods::multimethod fdiv => qw(Math::BigNum *) => sub {
2557             Math::BigNum->new($_[1])->bfdiv($_[0])->binv;
2558             };
2559              
2560             Class::Multimethods::multimethod fdiv => qw(Math::BigNum Math::BigNum::Inf) => \&zero;
2561             Class::Multimethods::multimethod fdiv => qw(Math::BigNum Math::BigNum::Nan) => \&nan;
2562              
2563             =head2 bfdiv
2564              
2565             $x->bfdiv(BigNum) # => BigNum | Nan | Inf
2566             $x->bfdiv(Scalar) # => BigNum | Nan | Inf
2567              
2568             Floating-point division of C by C, changing C in-place.
2569              
2570             =cut
2571              
2572             Class::Multimethods::multimethod bfdiv => qw(Math::BigNum Math::BigNum) => sub {
2573             my ($x, $y) = @_;
2574             my $r = _big2mpfr($x);
2575             Math::MPFR::Rmpfr_div_q($r, $r, $$y, $ROUND);
2576             _mpfr2x($x, $r);
2577             };
2578              
2579             Class::Multimethods::multimethod bfdiv => qw(Math::BigNum $) => sub {
2580             my ($x, $y) = @_;
2581              
2582             my $r = _big2mpfr($x);
2583             if (CORE::int($y) eq $y and $y >= MIN_SI and $y <= MAX_UI) {
2584             $y >= 0
2585             ? Math::MPFR::Rmpfr_div_ui($r, $r, $y, $ROUND)
2586             : Math::MPFR::Rmpfr_div_si($r, $r, $y, $ROUND);
2587             }
2588             else {
2589             Math::MPFR::Rmpfr_div($r, $r, _str2mpfr($y) // (return $x->bfdiv(Math::BigNum->new($y))), $ROUND);
2590             }
2591             _mpfr2x($x, $r);
2592             };
2593              
2594             Class::Multimethods::multimethod bfdiv => qw(Math::BigNum *) => sub {
2595             $_[0]->bfdiv(Math::BigNum->new($_[1]));
2596             };
2597              
2598             Class::Multimethods::multimethod bfdiv => qw(Math::BigNum Math::BigNum::Inf) => \&bzero;
2599             Class::Multimethods::multimethod bfdiv => qw(Math::BigNum Math::BigNum::Nan) => \&bnan;
2600              
2601             =head2 fpow
2602              
2603             $x->fpow(BigNum) # => BigNum | Inf | Nan
2604             $x->fpow(Scalar) # => BigNum | Inf | Nan
2605              
2606             Raises C to power C. Returns Nan when C is negative
2607             and C is not an integer.
2608              
2609             =cut
2610              
2611             Class::Multimethods::multimethod fpow => qw(Math::BigNum Math::BigNum) => sub {
2612             my ($x, $y) = @_;
2613             my $r = _big2mpfr($x);
2614             Math::MPFR::Rmpfr_pow($r, $r, _big2mpfr($y), $ROUND);
2615             _mpfr2big($r);
2616             };
2617              
2618             Class::Multimethods::multimethod fpow => qw(Math::BigNum $) => sub {
2619             my ($x, $y) = @_;
2620             my $r = _big2mpfr($x);
2621             if (CORE::int($y) eq $y and $y >= MIN_SI and $y <= MAX_UI) {
2622             $y >= 0
2623             ? Math::MPFR::Rmpfr_pow_ui($r, $r, $y, $ROUND)
2624             : Math::MPFR::Rmpfr_pow_si($r, $r, $y, $ROUND);
2625             }
2626             else {
2627             Math::MPFR::Rmpfr_pow($r, $r, _str2mpfr($y) // (return $x->fpow(Math::BigNum->new($y))), $ROUND);
2628             }
2629             _mpfr2big($r);
2630             };
2631              
2632             Class::Multimethods::multimethod fpow => qw(Math::BigNum *) => sub {
2633             $_[0]->fpow(Math::BigNum->new($_[1]));
2634             };
2635              
2636             Class::Multimethods::multimethod fpow => qw(Math::BigNum Math::BigNum::Inf) => sub {
2637             $_[0]->pow($_[1]);
2638             };
2639              
2640             Class::Multimethods::multimethod fpow => qw(Math::BigNum Math::BigNum::Nan) => \&nan;
2641              
2642             =head2 bfpow
2643              
2644             $x->bfpow(BigNum) # => BigNum | Inf | Nan
2645             $x->bfpow(Scalar) # => BigNum | Inf | Nan
2646              
2647             Raises C to power C, changing C in-place. Promotes C to Nan when C is negative
2648             and C is not an integer.
2649              
2650             =cut
2651              
2652             Class::Multimethods::multimethod bfpow => qw(Math::BigNum Math::BigNum) => sub {
2653             my ($x, $y) = @_;
2654             my $r = _big2mpfr($x);
2655             Math::MPFR::Rmpfr_pow($r, $r, _big2mpfr($y), $ROUND);
2656             _mpfr2x($x, $r);
2657             };
2658              
2659             Class::Multimethods::multimethod bfpow => qw(Math::BigNum $) => sub {
2660             my ($x, $y) = @_;
2661             my $r = _big2mpfr($x);
2662             if (CORE::int($y) eq $y and $y >= MIN_SI and $y <= MAX_UI) {
2663             $y >= 0
2664             ? Math::MPFR::Rmpfr_pow_ui($r, $r, $y, $ROUND)
2665             : Math::MPFR::Rmpfr_pow_si($r, $r, $y, $ROUND);
2666             }
2667             else {
2668             Math::MPFR::Rmpfr_pow($r, $r, _str2mpfr($y) // (return $x->fpow(Math::BigNum->new($y))), $ROUND);
2669             }
2670             _mpfr2x($x, $r);
2671             };
2672              
2673             Class::Multimethods::multimethod bfpow => qw(Math::BigNum *) => sub {
2674             $_[0]->bfpow(Math::BigNum->new($_[1]));
2675             };
2676              
2677             Class::Multimethods::multimethod bfpow => qw(Math::BigNum Math::BigNum::Inf) => sub {
2678             $_[0]->bpow($_[1]);
2679             };
2680              
2681             Class::Multimethods::multimethod bfpow => qw(Math::BigNum Math::BigNum::Nan) => \&bnan;
2682              
2683             =head2 fmod
2684              
2685             $x->fmod(BigNum) # => BigNum | Nan
2686             $x->fmod(Scalar) # => BigNum | Nan
2687              
2688             The remainder of C when is divided by C. Nan is returned when C is zero.
2689              
2690             =cut
2691              
2692             Class::Multimethods::multimethod fmod => qw(Math::BigNum Math::BigNum) => sub {
2693             my ($x, $y) = @_;
2694              
2695             $x = _big2mpfr($x);
2696             $y = _big2mpfr($y);
2697              
2698             Math::MPFR::Rmpfr_fmod($x, $x, $y, $ROUND);
2699              
2700             my $sign_r = Math::MPFR::Rmpfr_sgn($x);
2701             if (!$sign_r) {
2702             return (zero); # return faster
2703             }
2704             elsif ($sign_r > 0 xor Math::MPFR::Rmpfr_sgn($y) > 0) {
2705             Math::MPFR::Rmpfr_add($x, $x, $y, $ROUND);
2706             }
2707              
2708             _mpfr2big($x);
2709             };
2710              
2711             Class::Multimethods::multimethod fmod => qw(Math::BigNum $) => sub {
2712             my ($x, $y) = @_;
2713              
2714             my $m = _str2mpfr($y) // return $x->fmod(Math::BigNum->new($y));
2715             my $r = _big2mpfr($x);
2716              
2717             Math::MPFR::Rmpfr_fmod($r, $r, $m, $ROUND);
2718              
2719             my $sign_r = Math::MPFR::Rmpfr_sgn($r);
2720             if (!$sign_r) {
2721             return (zero); # return faster
2722             }
2723             elsif ($sign_r > 0 xor Math::MPFR::Rmpfr_sgn($m) > 0) {
2724             Math::MPFR::Rmpfr_add($r, $r, $m, $ROUND);
2725             }
2726              
2727             _mpfr2big($r);
2728             };
2729              
2730             Class::Multimethods::multimethod fmod => qw(Math::BigNum *) => sub {
2731             $_[0]->fmod(Math::BigNum->new($_[1]));
2732             };
2733              
2734             Class::Multimethods::multimethod fmod => qw(Math::BigNum Math::BigNum::Inf) => sub {
2735             $_[0]->copy->bmod($_[1]);
2736             };
2737              
2738             Class::Multimethods::multimethod fmod => qw(Math::BigNum Math::BigNum::Nan) => \&nan;
2739              
2740             =head2 bfmod
2741              
2742             $x->bfmod(BigNum) # => BigNum | Nan
2743             $x->bfmod(Scalar) # => BigNum | Nan
2744              
2745             The remainder of C when is divided by C, changing C in-place.
2746             Promotes C to Nan when C is zero.
2747              
2748             =cut
2749              
2750             Class::Multimethods::multimethod bfmod => qw(Math::BigNum Math::BigNum) => sub {
2751             my ($x, $y) = @_;
2752              
2753             my $r = _big2mpfr($x);
2754             my $m = _big2mpfr($y);
2755              
2756             Math::MPFR::Rmpfr_fmod($r, $r, $m, $ROUND);
2757              
2758             my $sign_r = Math::MPFR::Rmpfr_sgn($r);
2759             if (!$sign_r) {
2760             return $x->bzero; # return faster
2761             }
2762             elsif ($sign_r > 0 xor Math::MPFR::Rmpfr_sgn($m) > 0) {
2763             Math::MPFR::Rmpfr_add($r, $r, $m, $ROUND);
2764             }
2765              
2766             _mpfr2x($x, $r);
2767             };
2768              
2769             Class::Multimethods::multimethod bfmod => qw(Math::BigNum $) => sub {
2770             my ($x, $y) = @_;
2771              
2772             my $m = _str2mpfr($y) // return $x->bfmod(Math::BigNum->new($y));
2773             my $r = _big2mpfr($x);
2774              
2775             Math::MPFR::Rmpfr_fmod($r, $r, $m, $ROUND);
2776              
2777             my $sign_r = Math::MPFR::Rmpfr_sgn($r);
2778             if (!$sign_r) {
2779             return $x->bzero; # return faster
2780             }
2781             elsif ($sign_r > 0 xor Math::MPFR::Rmpfr_sgn($m) > 0) {
2782             Math::MPFR::Rmpfr_add($r, $r, $m, $ROUND);
2783             }
2784              
2785             _mpfr2x($x, $r);
2786             };
2787              
2788             Class::Multimethods::multimethod bfmod => qw(Math::BigNum *) => sub {
2789             $_[0]->bfmod(Math::BigNum->new($_[1]));
2790             };
2791              
2792             Class::Multimethods::multimethod bfmod => qw(Math::BigNum Math::BigNum::Inf) => sub {
2793             $_[0]->bmod($_[1]);
2794             };
2795              
2796             Class::Multimethods::multimethod bfmod => qw(Math::BigNum Math::BigNum::Nan) => \&bnan;
2797              
2798             =head2 sqrt
2799              
2800             $x->sqrt # => BigNum | Nan
2801             sqrt($x) # => BigNum | Nan
2802              
2803             Square root of C. Returns Nan when C is negative.
2804              
2805             =cut
2806              
2807             sub sqrt {
2808             my ($x) = @_;
2809             my $r = _big2mpfr($x);
2810             Math::MPFR::Rmpfr_sqrt($r, $r, $ROUND);
2811             _mpfr2big($r);
2812             }
2813              
2814             =head2 bsqrt
2815              
2816             $x->bsqrt # => BigNum | Nan
2817              
2818             Square root of C, changing C in-place. Promotes C to Nan when C is negative.
2819              
2820             =cut
2821              
2822             sub bsqrt {
2823             my ($x) = @_;
2824             my $r = _big2mpfr($x);
2825             Math::MPFR::Rmpfr_sqrt($r, $r, $ROUND);
2826             _mpfr2x($x, $r);
2827             }
2828              
2829             =head2 cbrt
2830              
2831             $x->cbrt # => BigNum | Nan
2832              
2833             Cube root of C. Returns Nan when C is negative.
2834              
2835             =cut
2836              
2837             sub cbrt {
2838             my ($x) = @_;
2839             my $r = _big2mpfr($x);
2840             Math::MPFR::Rmpfr_cbrt($r, $r, $ROUND);
2841             _mpfr2big($r);
2842             }
2843              
2844             =head2 root
2845              
2846             $x->root(BigNum) # => BigNum | Nan
2847             $x->root(Scalar) # => BigNum | Nan
2848              
2849             Nth root of C. Returns Nan when C is negative.
2850              
2851             =cut
2852              
2853             Class::Multimethods::multimethod root => qw(Math::BigNum Math::BigNum) => sub {
2854             my ($x, $y) = @_;
2855              
2856             if (Math::GMPq::Rmpq_sgn($$y) > 0 and Math::GMPq::Rmpq_integer_p($$y)) {
2857             $x = _big2mpfr($x);
2858             Math::MPFR::Rmpfr_root($x, $x, Math::GMPq::Rmpq_get_d($$y), $ROUND);
2859             _mpfr2big($x);
2860             }
2861             else {
2862             $x->pow($y->inv);
2863             }
2864             };
2865              
2866             =for comment
2867             Class::Multimethods::multimethod root => qw(Math::BigNum Math::BigNum::Complex) => sub {
2868             Math::BigNum::Complex->new($_[0])->pow($_[1]->inv);
2869             };
2870             =cut
2871              
2872             Class::Multimethods::multimethod root => qw(Math::BigNum $) => sub {
2873             my ($x, $y) = @_;
2874              
2875             if (CORE::int($y) eq $y and $y > 0 and $y <= MAX_UI) {
2876             $x = _big2mpfr($x);
2877             Math::MPFR::Rmpfr_root($x, $x, $y, $ROUND);
2878             _mpfr2big($x);
2879             }
2880             else {
2881             $x->pow(Math::BigNum->new($y)->binv);
2882             }
2883             };
2884              
2885             Class::Multimethods::multimethod root => qw(Math::BigNum *) => sub {
2886             $_[0]->root(Math::BigNum->new($_[1]));
2887             };
2888              
2889             Class::Multimethods::multimethod root => qw(Math::BigNum Math::BigNum::Inf) => \&one;
2890             Class::Multimethods::multimethod root => qw(Math::BigNum Math::BigNum::Nan) => \&nan;
2891              
2892             =head2 broot
2893              
2894             $x->broot(BigNum) # => BigNum | Nan
2895             $x->broot(Scalar) # => BigNum(1)
2896              
2897             Nth root of C, changing C in-place. Promotes
2898             C to Nan when C is negative.
2899              
2900             =cut
2901              
2902             Class::Multimethods::multimethod broot => qw(Math::BigNum Math::BigNum) => sub {
2903             my ($x, $y) = @_;
2904              
2905             if (Math::GMPq::Rmpq_sgn($$y) > 0 and Math::GMPq::Rmpq_integer_p($$y)) {
2906             my $f = _big2mpfr($x);
2907             Math::MPFR::Rmpfr_root($f, $f, Math::GMPq::Rmpq_get_d($$y), $ROUND);
2908             _mpfr2x($x, $f);
2909             }
2910             else {
2911             $x->pow($y->inv);
2912             }
2913             };
2914              
2915             Class::Multimethods::multimethod broot => qw(Math::BigNum $) => sub {
2916             my ($x, $y) = @_;
2917              
2918             if (CORE::int($y) eq $y and $y > 0 and $y <= MAX_UI) {
2919             my $f = _big2mpfr($x);
2920             Math::MPFR::Rmpfr_root($f, $f, $y, $ROUND);
2921             _mpfr2x($x, $f);
2922             }
2923             else {
2924             $x->bpow(Math::BigNum->new($y)->binv);
2925             }
2926             };
2927              
2928             Class::Multimethods::multimethod broot => qw(Math::BigNum *) => sub {
2929             $_[0]->broot(Math::BigNum->new($_[1]));
2930             };
2931              
2932             =for comment
2933             Class::Multimethods::multimethod broot => qw(Math::BigNum Math::BigNum::Complex) => sub {
2934             my $complex = Math::BigNum::Complex->new($_[0])->bpow($_[1]->inv);
2935             _big2cplx($_[0], $complex);
2936             };
2937             =cut
2938              
2939             Class::Multimethods::multimethod broot => qw(Math::BigNum Math::BigNum::Inf) => \&bone;
2940             Class::Multimethods::multimethod broot => qw(Math::BigNum Math::BigNum::Nan) => \&bnan;
2941              
2942             =head2 ln
2943              
2944             $x->ln # => BigNum | Nan
2945              
2946             Logarithm of C in base I. Returns Nan when C is negative.
2947              
2948             =cut
2949              
2950             sub ln {
2951             my ($x) = @_;
2952             my $r = _big2mpfr($x);
2953             Math::MPFR::Rmpfr_log($r, $r, $ROUND);
2954             _mpfr2big($r);
2955             }
2956              
2957             =head2 bln
2958              
2959             $x->bln # => BigNum | Nan
2960              
2961             Logarithm of C in base I, changing the C in-place.
2962             Promotes C to Nan when C is negative.
2963              
2964             =cut
2965              
2966             sub bln {
2967             my ($x) = @_;
2968             my $r = _big2mpfr($x);
2969             Math::MPFR::Rmpfr_log($r, $r, $ROUND);
2970             _mpfr2x($x, $r);
2971             }
2972              
2973             =head2 log
2974              
2975             $x->log # => BigNum | Nan
2976             $x->log(BigNum) # => BigNum | Nan
2977             $x->log(Scalar) # => BigNum | Nan
2978             log(BigNum) # => BigNum | Nan
2979              
2980             Logarithm of C in base C. When C is not specified, it defaults to base e.
2981             Returns Nan when C is negative and -Inf when C is zero.
2982              
2983             =cut
2984              
2985             # Probably we should add cases when the base equals zero.
2986              
2987             # Example:
2988             # log(+42) / log(0) = 0
2989             # log(-42) / log(0) = 0
2990             # log( 0 ) / log(0) = undefined
2991              
2992             Class::Multimethods::multimethod log => qw(Math::BigNum Math::BigNum) => sub {
2993             my ($x, $y) = @_;
2994              
2995             # log(x,base) = log(x)/log(base)
2996             my $r = _big2mpfr($x);
2997             Math::MPFR::Rmpfr_log($r, $r, $ROUND);
2998             my $baseln = _big2mpfr($y);
2999             Math::MPFR::Rmpfr_log($baseln, $baseln, $ROUND);
3000             Math::MPFR::Rmpfr_div($r, $r, $baseln, $ROUND);
3001              
3002             _mpfr2big($r);
3003             };
3004              
3005             Class::Multimethods::multimethod log => qw(Math::BigNum $) => sub {
3006             my ($x, $y) = @_;
3007              
3008             if (CORE::int($y) eq $y and $y == 2) {
3009             my $r = _big2mpfr($x);
3010             Math::MPFR::Rmpfr_log2($r, $r, $ROUND);
3011             _mpfr2big($r);
3012             }
3013             elsif (CORE::int($y) eq $y and $y == 10) {
3014             my $r = _big2mpfr($x);
3015             Math::MPFR::Rmpfr_log10($r, $r, $ROUND);
3016             _mpfr2big($r);
3017             }
3018             else {
3019             my $baseln = _str2mpfr($y) // return $x->log(Math::BigNum->new($y));
3020             my $r = _big2mpfr($x);
3021             Math::MPFR::Rmpfr_log($r, $r, $ROUND);
3022             Math::MPFR::Rmpfr_log($baseln, $baseln, $ROUND);
3023             Math::MPFR::Rmpfr_div($r, $r, $baseln, $ROUND);
3024             _mpfr2big($r);
3025             }
3026             };
3027              
3028             Class::Multimethods::multimethod log => qw(Math::BigNum) => \&ln;
3029              
3030             Class::Multimethods::multimethod log => qw(Math::BigNum *) => sub {
3031             $_[0]->log(Math::BigNum->new($_[1]));
3032             };
3033              
3034             Class::Multimethods::multimethod log => qw(Math::BigNum Math::BigNum::Nan) => \&nan;
3035              
3036             # log(+/-Inf) = +Inf
3037             # log(-42) / log(+/-Inf) = 0
3038             # log(+42) / log(+/-Inf) = 0
3039             # log(0) / log(+/-Inf) = NaN
3040              
3041             Class::Multimethods::multimethod log => qw(Math::BigNum Math::BigNum::Inf) => sub {
3042             Math::GMPq::Rmpq_sgn(${$_[0]}) == 0 ? nan() : zero();
3043             };
3044              
3045             =head2 blog
3046              
3047             $x->blog # => BigNum | Nan
3048             $x->blog(BigNum) # => BigNum | Nan
3049             $x->log(Scalar) # => BigNum | Nan
3050              
3051             Logarithm of C in base C, changing the C in-place.
3052             When C is not specified, it defaults to base I.
3053              
3054             =cut
3055              
3056             Class::Multimethods::multimethod blog => qw(Math::BigNum $) => sub {
3057             my ($x, $y) = @_;
3058              
3059             if (CORE::int($y) eq $y and $y == 2) {
3060             my $r = _big2mpfr($x);
3061             Math::MPFR::Rmpfr_log2($r, $r, $ROUND);
3062             _mpfr2x($x, $r);
3063              
3064             }
3065             elsif (CORE::int($y) eq $y and $y == 10) {
3066             my $r = _big2mpfr($x);
3067             Math::MPFR::Rmpfr_log10($r, $r, $ROUND);
3068             _mpfr2x($x, $r);
3069             }
3070             else {
3071             my $baseln = _str2mpfr($y) // return $x->blog(Math::BigNum->new($y));
3072             my $r = _big2mpfr($x);
3073             Math::MPFR::Rmpfr_log($r, $r, $ROUND);
3074             Math::MPFR::Rmpfr_log($baseln, $baseln, $ROUND);
3075             Math::MPFR::Rmpfr_div($r, $r, $baseln, $ROUND);
3076             _mpfr2x($x, $r);
3077             }
3078             };
3079              
3080             Class::Multimethods::multimethod blog => qw(Math::BigNum Math::BigNum) => sub {
3081             $_[0]->blog(Math::GMPq::Rmpq_get_d(${$_[1]}));
3082             };
3083              
3084             Class::Multimethods::multimethod blog => qw(Math::BigNum) => \&bln;
3085              
3086             Class::Multimethods::multimethod blog => qw(Math::BigNum *) => sub {
3087             $_[0]->blog(Math::BigNum->new($_[1]));
3088             };
3089              
3090             Class::Multimethods::multimethod blog => qw(Math::BigNum Math::BigNum::Nan) => \&bnan;
3091              
3092             Class::Multimethods::multimethod blog => qw(Math::BigNum Math::BigNum::Inf) => sub {
3093             Math::GMPq::Rmpq_sgn(${$_[0]}) == 0 ? $_[0]->bnan : $_[0]->bzero;
3094             };
3095              
3096             =head2 log2
3097              
3098             $x->log2 # => BigNum | Nan
3099              
3100             Logarithm of C in base 2. Returns Nan when C is negative.
3101              
3102             =cut
3103              
3104             sub log2 {
3105             my ($x) = @_;
3106             my $r = _big2mpfr($x);
3107             Math::MPFR::Rmpfr_log2($r, $r, $ROUND);
3108             _mpfr2big($r);
3109             }
3110              
3111             =head2 log10
3112              
3113             $x->log10 # => BigNum | Nan
3114              
3115             Logarithm of C in base 10. Returns Nan when C is negative.
3116              
3117             =cut
3118              
3119             sub log10 {
3120             my ($x) = @_;
3121             my $r = _big2mpfr($x);
3122             Math::MPFR::Rmpfr_log10($r, $r, $ROUND);
3123             _mpfr2big($r);
3124             }
3125              
3126             =head2 lgrt
3127              
3128             $x->lgrt # => BigNum | Nan
3129              
3130             Logarithmic-root of C, which is the largest solution to C, where C is known.
3131              
3132             Example:
3133              
3134             100->lgrt # solves for x in `x^x = 100` and returns: `3.59728...`
3135              
3136             =cut
3137              
3138             sub lgrt {
3139             my ($x) = @_;
3140              
3141             my $d = _big2mpfr($x);
3142             Math::MPFR::Rmpfr_log($d, $d, $ROUND);
3143              
3144             my $p = Math::MPFR::Rmpfr_init2($PREC);
3145             Math::MPFR::Rmpfr_ui_pow_ui($p, 10, CORE::int($PREC / 4), $ROUND);
3146             Math::MPFR::Rmpfr_ui_div($p, 1, $p, $ROUND);
3147              
3148             $x = Math::MPFR::Rmpfr_init2($PREC);
3149             Math::MPFR::Rmpfr_set_ui($x, 1, $ROUND);
3150              
3151             my $y = Math::MPFR::Rmpfr_init2($PREC);
3152             Math::MPFR::Rmpfr_set_ui($y, 0, $ROUND);
3153              
3154             my $count = 0;
3155             my $tmp = Math::MPFR::Rmpfr_init2($PREC);
3156              
3157             while (1) {
3158             Math::MPFR::Rmpfr_sub($tmp, $x, $y, $ROUND);
3159             Math::MPFR::Rmpfr_cmpabs($tmp, $p) <= 0 and last;
3160              
3161             Math::MPFR::Rmpfr_set($y, $x, $ROUND);
3162              
3163             Math::MPFR::Rmpfr_log($tmp, $x, $ROUND);
3164             Math::MPFR::Rmpfr_add_ui($tmp, $tmp, 1, $ROUND);
3165              
3166             Math::MPFR::Rmpfr_add($x, $x, $d, $ROUND);
3167             Math::MPFR::Rmpfr_div($x, $x, $tmp, $ROUND);
3168             last if ++$count > $PREC;
3169             }
3170              
3171             _mpfr2big($x);
3172             }
3173              
3174             =head2 lambert_w
3175              
3176             $x->lambert_w # => BigNum | Nan
3177              
3178             The Lambert-W function, defined in real numbers. The value of C should not be less than C<-1/e>.
3179              
3180             Example:
3181              
3182             100->log->lambert_w->exp # solves for x in `x^x = 100` and returns: `3.59728...`
3183              
3184             =cut
3185              
3186             sub lambert_w {
3187             my ($x) = @_;
3188              
3189             my $sgn = Math::GMPq::Rmpq_sgn($$x);
3190              
3191             $sgn == 0 and return zero();
3192             Math::GMPq::Rmpq_equal($$x, $MONE) && return nan();
3193              
3194             my $d = _big2mpfr($x);
3195              
3196             $PREC = CORE::int($PREC);
3197             Math::MPFR::Rmpfr_ui_pow_ui((my $p = Math::MPFR::Rmpfr_init2($PREC)), 10, CORE::int($PREC / 4), $ROUND);
3198             Math::MPFR::Rmpfr_ui_div($p, 1, $p, $ROUND);
3199              
3200             Math::MPFR::Rmpfr_set_ui(($x = Math::MPFR::Rmpfr_init2($PREC)), 1, $ROUND);
3201             Math::MPFR::Rmpfr_set_ui((my $y = Math::MPFR::Rmpfr_init2($PREC)), 0, $ROUND);
3202              
3203             my $count = 0;
3204             my $tmp = Math::MPFR::Rmpfr_init2($PREC);
3205              
3206             while (1) {
3207             Math::MPFR::Rmpfr_sub($tmp, $x, $y, $ROUND);
3208             Math::MPFR::Rmpfr_cmpabs($tmp, $p) <= 0 and last;
3209              
3210             Math::MPFR::Rmpfr_set($y, $x, $ROUND);
3211              
3212             Math::MPFR::Rmpfr_log($tmp, $x, $ROUND);
3213             Math::MPFR::Rmpfr_add_ui($tmp, $tmp, 1, $ROUND);
3214              
3215             Math::MPFR::Rmpfr_add($x, $x, $d, $ROUND);
3216             Math::MPFR::Rmpfr_div($x, $x, $tmp, $ROUND);
3217             last if ++$count > $PREC;
3218             }
3219              
3220             Math::MPFR::Rmpfr_log($x, $x, $ROUND);
3221             _mpfr2big($x);
3222             }
3223              
3224             =head2 exp
3225              
3226             $x->exp # => BigNum
3227              
3228             Exponential of C in base e. (C)
3229              
3230             =cut
3231              
3232             sub exp {
3233             my $r = _big2mpfr($_[0]);
3234             Math::MPFR::Rmpfr_exp($r, $r, $ROUND);
3235             _mpfr2big($r);
3236             }
3237              
3238             =head2 bexp
3239              
3240             $x->bexp # => BigNum
3241              
3242             Exponential of C in base e, changing C in-place.
3243              
3244             =cut
3245              
3246             sub bexp {
3247             my ($x) = @_;
3248             my $r = _big2mpfr($x);
3249             Math::MPFR::Rmpfr_exp($r, $r, $ROUND);
3250             _mpfr2x($x, $r);
3251             }
3252              
3253             =head2 exp2
3254              
3255             $x->exp2 # => BigNum
3256              
3257             Exponential of C in base 2. (C<2^x>)
3258              
3259             =cut
3260              
3261             sub exp2 {
3262             my $r = _big2mpfr($_[0]);
3263             Math::MPFR::Rmpfr_exp2($r, $r, $ROUND);
3264             _mpfr2big($r);
3265             }
3266              
3267             =head2 exp10
3268              
3269             $x->exp10 # => BigNum
3270              
3271             Exponential of C in base 10. (C<10^x>)
3272              
3273             =cut
3274              
3275             sub exp10 {
3276             my $r = _big2mpfr($_[0]);
3277             Math::MPFR::Rmpfr_exp10($r, $r, $ROUND);
3278             _mpfr2big($r);
3279             }
3280              
3281             =head1 * Trigonometry
3282              
3283             =cut
3284              
3285             =head2 sin
3286              
3287             $x->sin # => BigNum
3288              
3289             Returns the sine of C.
3290              
3291             =cut
3292              
3293             sub sin {
3294             my $r = _big2mpfr($_[0]);
3295             Math::MPFR::Rmpfr_sin($r, $r, $ROUND);
3296             _mpfr2big($r);
3297             }
3298              
3299             =head2 asin
3300              
3301             $x->asin # => BigNum | Nan
3302              
3303             Returns the inverse sine of C.
3304             Returns Nan for x < -1 or x > 1.
3305              
3306             =cut
3307              
3308             sub asin {
3309             my ($x) = @_;
3310             my $r = _big2mpfr($x);
3311             Math::MPFR::Rmpfr_asin($r, $r, $ROUND);
3312             _mpfr2big($r);
3313             }
3314              
3315             =head2 sinh
3316              
3317             $x->sinh # => BigNum
3318              
3319             Returns the hyperbolic sine of C.
3320              
3321             =cut
3322              
3323             sub sinh {
3324             my $r = _big2mpfr($_[0]);
3325             Math::MPFR::Rmpfr_sinh($r, $r, $ROUND);
3326             _mpfr2big($r);
3327             }
3328              
3329             =head2 asinh
3330              
3331             $x->asinh # => BigNum
3332              
3333             Returns the inverse hyperbolic sine of C.
3334              
3335             =cut
3336              
3337             sub asinh {
3338             my $r = _big2mpfr($_[0]);
3339             Math::MPFR::Rmpfr_asinh($r, $r, $ROUND);
3340             _mpfr2big($r);
3341             }
3342              
3343             =head2 cos
3344              
3345             $x->cos # => BigNum
3346              
3347             Returns the cosine of C.
3348              
3349             =cut
3350              
3351             sub cos {
3352             my $r = _big2mpfr($_[0]);
3353             Math::MPFR::Rmpfr_cos($r, $r, $ROUND);
3354             _mpfr2big($r);
3355             }
3356              
3357             =head2 acos
3358              
3359             $x->acos # => BigNum | Nan
3360              
3361             Returns the inverse cosine of C.
3362             Returns Nan for x < -1 or x > 1.
3363              
3364             =cut
3365              
3366             sub acos {
3367             my ($x) = @_;
3368             my $r = _big2mpfr($x);
3369             Math::MPFR::Rmpfr_acos($r, $r, $ROUND);
3370             _mpfr2big($r);
3371             }
3372              
3373             =head2 cosh
3374              
3375             $x->cosh # => BigNum
3376              
3377             Returns the hyperbolic cosine of C.
3378              
3379             =cut
3380              
3381             sub cosh {
3382             my $r = _big2mpfr($_[0]);
3383             Math::MPFR::Rmpfr_cosh($r, $r, $ROUND);
3384             _mpfr2big($r);
3385             }
3386              
3387             =head2 acosh
3388              
3389             $x->acosh # => BigNum | Nan
3390              
3391             Returns the inverse hyperbolic cosine of C.
3392             Returns Nan for x < 1.
3393              
3394             =cut
3395              
3396             sub acosh {
3397             my ($x) = @_;
3398             my $r = _big2mpfr($x);
3399             Math::MPFR::Rmpfr_acosh($r, $r, $ROUND);
3400             _mpfr2big($r);
3401             }
3402              
3403             =head2 tan
3404              
3405             $x->tan # => BigNum
3406              
3407             Returns the tangent of C.
3408              
3409             =cut
3410              
3411             sub tan {
3412             my $r = _big2mpfr($_[0]);
3413             Math::MPFR::Rmpfr_tan($r, $r, $ROUND);
3414             _mpfr2big($r);
3415             }
3416              
3417             =head2 atan
3418              
3419             $x->atan # => BigNum
3420              
3421             Returns the inverse tangent of C.
3422              
3423             =cut
3424              
3425             sub atan {
3426             my $r = _big2mpfr($_[0]);
3427             Math::MPFR::Rmpfr_atan($r, $r, $ROUND);
3428             _mpfr2big($r);
3429             }
3430              
3431             =head2 tanh
3432              
3433             $x->tanh # => BigNum
3434              
3435             Returns the hyperbolic tangent of C.
3436              
3437             =cut
3438              
3439             sub tanh {
3440             my $r = _big2mpfr($_[0]);
3441             Math::MPFR::Rmpfr_tanh($r, $r, $ROUND);
3442             _mpfr2big($r);
3443             }
3444              
3445             =head2 atanh
3446              
3447             $x->atanh # => BigNum | Nan
3448              
3449             Returns the inverse hyperbolic tangent of C.
3450             Returns Nan for x <= -1 or x >= 1.
3451              
3452             =cut
3453              
3454             sub atanh {
3455             my ($x) = @_;
3456             my $r = _big2mpfr($x);
3457             Math::MPFR::Rmpfr_atanh($r, $r, $ROUND);
3458             _mpfr2big($r);
3459             }
3460              
3461             =head2 sec
3462              
3463             $x->sec # => BigNum
3464              
3465             Returns the secant of C.
3466              
3467             =cut
3468              
3469             sub sec {
3470             my $r = _big2mpfr($_[0]);
3471             Math::MPFR::Rmpfr_sec($r, $r, $ROUND);
3472             _mpfr2big($r);
3473             }
3474              
3475             =head2 asec
3476              
3477             $x->asec # => BigNum | Nan
3478              
3479             Returns the inverse secant of C.
3480             Returns Nan for x > -1 and x < 1.
3481              
3482             Defined as:
3483              
3484             asec(x) = acos(1/x)
3485              
3486             =cut
3487              
3488             #
3489             ## asec(x) = acos(1/x)
3490             #
3491             sub asec {
3492             my ($x) = @_;
3493             my $r = _big2mpfr($x);
3494             Math::MPFR::Rmpfr_ui_div($r, 1, $r, $ROUND);
3495             Math::MPFR::Rmpfr_acos($r, $r, $ROUND);
3496             _mpfr2big($r);
3497             }
3498              
3499             =head2 sech
3500              
3501             $x->sech # => BigNum
3502              
3503             Returns the hyperbolic secant of C.
3504              
3505             =cut
3506              
3507             sub sech {
3508             my $r = _big2mpfr($_[0]);
3509             Math::MPFR::Rmpfr_sech($r, $r, $ROUND);
3510             _mpfr2big($r);
3511             }
3512              
3513             =head2 asech
3514              
3515             $x->asech # => BigNum | Nan
3516              
3517             Returns the inverse hyperbolic secant of C.
3518             Returns a Nan for x < 0 or x > 1.
3519              
3520             Defined as:
3521              
3522             asech(x) = acosh(1/x)
3523              
3524             =cut
3525              
3526             #
3527             ## asech(x) = acosh(1/x)
3528             #
3529             sub asech {
3530             my ($x) = @_;
3531             my $r = _big2mpfr($x);
3532             Math::MPFR::Rmpfr_ui_div($r, 1, $r, $ROUND);
3533             Math::MPFR::Rmpfr_acosh($r, $r, $ROUND);
3534             _mpfr2big($r);
3535             }
3536              
3537             =head2 csc
3538              
3539             $x->csc # => BigNum
3540              
3541             Returns the cosecant of C.
3542              
3543             =cut
3544              
3545             sub csc {
3546             my $r = _big2mpfr($_[0]);
3547             Math::MPFR::Rmpfr_csc($r, $r, $ROUND);
3548             _mpfr2big($r);
3549             }
3550              
3551             =head2 acsc
3552              
3553             $x->acsc # => BigNum | Nan
3554              
3555             Returns the inverse cosecant of C.
3556             Returns Nan for x > -1 and x < 1.
3557              
3558             Defined as:
3559              
3560             acsc(x) = asin(1/x)
3561              
3562             =cut
3563              
3564             #
3565             ## acsc(x) = asin(1/x)
3566             #
3567             sub acsc {
3568             my ($x) = @_;
3569             my $r = _big2mpfr($x);
3570             Math::MPFR::Rmpfr_ui_div($r, 1, $r, $ROUND);
3571             Math::MPFR::Rmpfr_asin($r, $r, $ROUND);
3572             _mpfr2big($r);
3573             }
3574              
3575             =head2 csch
3576              
3577             $x->csch # => BigNum
3578              
3579             Returns the hyperbolic cosecant of C.
3580              
3581             =cut
3582              
3583             sub csch {
3584             my $r = _big2mpfr($_[0]);
3585             Math::MPFR::Rmpfr_csch($r, $r, $ROUND);
3586             _mpfr2big($r);
3587             }
3588              
3589             =head2 acsch
3590              
3591             $x->acsch # => BigNum
3592              
3593             Returns the inverse hyperbolic cosecant of C.
3594              
3595             Defined as:
3596              
3597             acsch(x) = asinh(1/x)
3598              
3599             =cut
3600              
3601             #
3602             ## acsch(x) = asinh(1/x)
3603             #
3604             sub acsch {
3605             my ($x) = @_;
3606             my $r = _big2mpfr($x);
3607             Math::MPFR::Rmpfr_ui_div($r, 1, $r, $ROUND);
3608             Math::MPFR::Rmpfr_asinh($r, $r, $ROUND);
3609             _mpfr2big($r);
3610             }
3611              
3612             =head2 cot
3613              
3614             $x->cot # => BigNum
3615              
3616             Returns the cotangent of C.
3617              
3618             =cut
3619              
3620             sub cot {
3621             my $r = _big2mpfr($_[0]);
3622             Math::MPFR::Rmpfr_cot($r, $r, $ROUND);
3623             _mpfr2big($r);
3624             }
3625              
3626             =head2 acot
3627              
3628             $x->acot # => BigNum
3629              
3630             Returns the inverse cotangent of C.
3631              
3632             Defined as:
3633              
3634             acot(x) = atan(1/x)
3635              
3636             =cut
3637              
3638             #
3639             ## acot(x) = atan(1/x)
3640             #
3641             sub acot {
3642             my ($x) = @_;
3643             my $r = _big2mpfr($x);
3644             Math::MPFR::Rmpfr_ui_div($r, 1, $r, $ROUND);
3645             Math::MPFR::Rmpfr_atan($r, $r, $ROUND);
3646             _mpfr2big($r);
3647             }
3648              
3649             =head2 coth
3650              
3651             $x->coth # => BigNum
3652              
3653             Returns the hyperbolic cotangent of C.
3654              
3655             =cut
3656              
3657             sub coth {
3658             my $r = _big2mpfr($_[0]);
3659             Math::MPFR::Rmpfr_coth($r, $r, $ROUND);
3660             _mpfr2big($r);
3661             }
3662              
3663             =head2 acoth
3664              
3665             $x->acoth # => BigNum
3666              
3667             Returns the inverse hyperbolic cotangent of C.
3668              
3669             Defined as:
3670              
3671             acoth(x) = atanh(1/x)
3672              
3673             =cut
3674              
3675             #
3676             ## acoth(x) = atanh(1/x)
3677             #
3678             sub acoth {
3679             my $r = _big2mpfr($_[0]);
3680             Math::MPFR::Rmpfr_ui_div($r, 1, $r, $ROUND);
3681             Math::MPFR::Rmpfr_atanh($r, $r, $ROUND);
3682             _mpfr2big($r);
3683             }
3684              
3685             =head2 atan2
3686              
3687             $x->atan2(BigNum) # => BigNum
3688             $x->atan2(Scalar) # => BigNum
3689              
3690             atan2(BigNum, BigNum) # => BigNum
3691             atan2(BigNum, Scalar) # => BigNum
3692             atan2(Scalar, BigNum) # => BigNum
3693              
3694             Arctangent of C and C. When C is -Inf returns PI when x >= 0, or C<-PI> when x < 0.
3695              
3696             =cut
3697              
3698             Class::Multimethods::multimethod atan2 => qw(Math::BigNum Math::BigNum) => sub {
3699             my $r = _big2mpfr($_[0]);
3700             Math::MPFR::Rmpfr_atan2($r, $r, _big2mpfr($_[1]), $ROUND);
3701             _mpfr2big($r);
3702             };
3703              
3704             Class::Multimethods::multimethod atan2 => qw(Math::BigNum $) => sub {
3705             my $f = _str2mpfr($_[1]) // return $_[0]->atan2(Math::BigNum->new($_[1]));
3706             my $r = _big2mpfr($_[0]);
3707             Math::MPFR::Rmpfr_atan2($r, $r, $f, $ROUND);
3708             _mpfr2big($r);
3709             };
3710              
3711             Class::Multimethods::multimethod atan2 => qw($ Math::BigNum) => sub {
3712             my $r = _str2mpfr($_[0]) // return Math::BigNum->new($_[0])->atan2($_[1]);
3713             Math::MPFR::Rmpfr_atan2($r, $r, _big2mpfr($_[1]), $ROUND);
3714             _mpfr2big($r);
3715             };
3716              
3717             Class::Multimethods::multimethod atan2 => qw(* Math::BigNum) => sub {
3718             Math::BigNum->new($_[0])->atan2($_[1]);
3719             };
3720              
3721             Class::Multimethods::multimethod atan2 => qw(Math::BigNum *) => sub {
3722             $_[0]->atan2(Math::BigNum->new($_[1]));
3723             };
3724              
3725             Class::Multimethods::multimethod atan2 => qw(Math::BigNum Math::BigNum::Inf) => sub {
3726             $_[1]->is_neg
3727             ? ((Math::GMPq::Rmpq_sgn(${$_[0]}) >= 0) ? pi() : (pi()->neg))
3728             : zero;
3729             };
3730              
3731             Class::Multimethods::multimethod atan2 => qw(Math::BigNum Math::BigNum::Nan) => \&nan;
3732              
3733             =head1 * Special methods
3734              
3735             =cut
3736              
3737             =head2 agm
3738              
3739             $x->agm(BigNum) # => BigNum
3740             $x->agm(Scalar) # => BigNum
3741              
3742             Arithmetic-geometric mean of C and C.
3743              
3744             =cut
3745              
3746             Class::Multimethods::multimethod agm => qw(Math::BigNum Math::BigNum) => sub {
3747             my $r = _big2mpfr($_[0]);
3748             Math::MPFR::Rmpfr_agm($r, $r, _big2mpfr($_[1]), $ROUND);
3749             _mpfr2big($r);
3750             };
3751              
3752             Class::Multimethods::multimethod agm => qw(Math::BigNum $) => sub {
3753             my $f = _str2mpfr($_[1]) // return $_[0]->agm(Math::BigNum->new($_[1]));
3754             my $r = _big2mpfr($_[0]);
3755             Math::MPFR::Rmpfr_agm($r, $r, $f, $ROUND);
3756             _mpfr2big($r);
3757             };
3758              
3759             Class::Multimethods::multimethod agm => qw(Math::BigNum *) => sub {
3760             $_[0]->agm(Math::BigNum->new($_[1]));
3761             };
3762              
3763             Class::Multimethods::multimethod agm => qw(Math::BigNum Math::BigNum::Inf) => sub {
3764             $_[1]->is_pos ? $_[1]->copy : nan();
3765             };
3766              
3767             Class::Multimethods::multimethod agm => qw(Math::BigNum Math::BigNum::Nan) => \&nan;
3768              
3769             =head2 hypot
3770              
3771             $x->hypot(BigNum) # => BigNum
3772             $x->hypot(Scalar) # => BigNum
3773              
3774             The value of the hypotenuse for catheti C and C. (C)
3775              
3776             =cut
3777              
3778             Class::Multimethods::multimethod hypot => qw(Math::BigNum Math::BigNum) => sub {
3779             my $r = _big2mpfr($_[0]);
3780             Math::MPFR::Rmpfr_hypot($r, $r, _big2mpfr($_[1]), $ROUND);
3781             _mpfr2big($r);
3782             };
3783              
3784             Class::Multimethods::multimethod hypot => qw(Math::BigNum $) => sub {
3785             my $f = _str2mpfr($_[1]) // return $_[0]->hypot(Math::BigNum->new($_[1]));
3786             my $r = _big2mpfr($_[0]);
3787             Math::MPFR::Rmpfr_hypot($r, $r, $f, $ROUND);
3788             _mpfr2big($r);
3789             };
3790              
3791             Class::Multimethods::multimethod hypot => qw(Math::BigNum *) => sub {
3792             $_[0]->hypot(Math::BigNum->new($_[1]));
3793             };
3794              
3795             Class::Multimethods::multimethod hypot => qw(Math::BigNum Math::BigNum::Inf) => \&inf;
3796             Class::Multimethods::multimethod hypot => qw(Math::BigNum Math::BigNum::Nan) => \&nan;
3797              
3798             =head2 gamma
3799              
3800             $x->gamma # => BigNum | Inf | Nan
3801              
3802             The Gamma function on C. Returns Inf when C is zero, and Nan when C is negative.
3803              
3804             =cut
3805              
3806             sub gamma {
3807             my $r = _big2mpfr($_[0]);
3808             Math::MPFR::Rmpfr_gamma($r, $r, $ROUND);
3809             _mpfr2big($r);
3810             }
3811              
3812             =head2 lngamma
3813              
3814             $x->lngamma # => BigNum | Inf
3815              
3816             The natural logarithm of the Gamma function on C.
3817             Returns Inf when C is negative or equal to zero.
3818              
3819             =cut
3820              
3821             sub lngamma {
3822             my $r = _big2mpfr($_[0]);
3823             Math::MPFR::Rmpfr_lngamma($r, $r, $ROUND);
3824             _mpfr2big($r);
3825             }
3826              
3827             =head2 lgamma
3828              
3829             $x->lgamma # => BigNum | Inf
3830              
3831             The logarithm of the absolute value of the Gamma function.
3832             Returns Inf when C is negative or equal to zero.
3833              
3834             =cut
3835              
3836             sub lgamma {
3837             my $r = _big2mpfr($_[0]);
3838             Math::MPFR::Rmpfr_lgamma($r, $r, $ROUND);
3839             _mpfr2big($r);
3840             }
3841              
3842             =head2 digamma
3843              
3844             $x->digamma # => BigNum | Inf | Nan
3845              
3846             The Digamma function (sometimes also called Psi).
3847             Returns Nan when C is negative, and -Inf when C is 0.
3848              
3849             =cut
3850              
3851             sub digamma {
3852             my $r = _big2mpfr($_[0]);
3853             Math::MPFR::Rmpfr_digamma($r, $r, $ROUND);
3854             _mpfr2big($r);
3855             }
3856              
3857             =head2 beta
3858              
3859             $x->beta(BigNum) # => BigNum | Inf | Nan
3860              
3861             The beta function (also called the Euler integral of the first kind).
3862              
3863             Defined as:
3864              
3865             beta(x,y) = gamma(x)*gamma(y) / gamma(x+y)
3866              
3867             for x > 0 and y > 0.
3868              
3869             =cut
3870              
3871             Class::Multimethods::multimethod beta => qw(Math::BigNum Math::BigNum) => sub {
3872             my ($x, $y) = @_;
3873              
3874             $x = _big2mpfr($x);
3875             $y = _big2mpfr($y);
3876              
3877             my $t = Math::MPFR::Rmpfr_init2($PREC);
3878             Math::MPFR::Rmpfr_add($t, $x, $y, $ROUND);
3879             Math::MPFR::Rmpfr_gamma($t, $t, $ROUND);
3880             Math::MPFR::Rmpfr_gamma($x, $x, $ROUND);
3881             Math::MPFR::Rmpfr_gamma($y, $y, $ROUND);
3882             Math::MPFR::Rmpfr_mul($x, $x, $y, $ROUND);
3883             Math::MPFR::Rmpfr_div($x, $x, $t, $ROUND);
3884              
3885             _mpfr2big($x);
3886             };
3887              
3888             Class::Multimethods::multimethod beta => qw(Math::BigNum *) => sub {
3889             Math::BigNum->new($_[1])->beta($_[0]);
3890             };
3891              
3892             Class::Multimethods::multimethod beta => qw(Math::BigNum Math::BigNum::Inf) => \&nan;
3893             Class::Multimethods::multimethod beta => qw(Math::BigNum Math::BigNum::Nan) => \&nan;
3894              
3895             =head2 zeta
3896              
3897             $x->zeta # => BigNum | Inf
3898              
3899             The Riemann zeta function at C. Returns Inf when C is 1.
3900              
3901             =cut
3902              
3903             sub zeta {
3904             my $r = _big2mpfr($_[0]);
3905             Math::MPFR::Rmpfr_zeta($r, $r, $ROUND);
3906             _mpfr2big($r);
3907             }
3908              
3909             =head2 eta
3910              
3911             $x->eta # => BigNum
3912              
3913             The Dirichlet eta function at C.
3914              
3915             Defined as:
3916              
3917             eta(1) = ln(2)
3918             eta(x) = (1 - 2**(1-x)) * zeta(x)
3919              
3920             =cut
3921              
3922             sub eta {
3923             my $r = _big2mpfr($_[0]);
3924              
3925             # Special case for eta(1) = log(2)
3926             if (!Math::MPFR::Rmpfr_cmp_ui($r, 1)) {
3927             Math::MPFR::Rmpfr_add_ui($r, $r, 1, $ROUND);
3928             Math::MPFR::Rmpfr_log($r, $r, $ROUND);
3929             return _mpfr2big($r);
3930             }
3931              
3932             my $p = Math::MPFR::Rmpfr_init2($PREC);
3933             Math::MPFR::Rmpfr_set($p, $r, $ROUND);
3934             Math::MPFR::Rmpfr_ui_sub($p, 1, $p, $ROUND);
3935             Math::MPFR::Rmpfr_ui_pow($p, 2, $p, $ROUND);
3936             Math::MPFR::Rmpfr_ui_sub($p, 1, $p, $ROUND);
3937              
3938             Math::MPFR::Rmpfr_zeta($r, $r, $ROUND);
3939             Math::MPFR::Rmpfr_mul($r, $r, $p, $ROUND);
3940              
3941             _mpfr2big($r);
3942             }
3943              
3944             =head2 bessel_j
3945              
3946             $x->bessel_j(BigNum) # => BigNum
3947             $x->bessel_j(Scalar) # => BigNum
3948              
3949             The first order Bessel function, C, where C is a signed integer.
3950              
3951             Example:
3952              
3953             $x->bessel_j($n) # represents J_n(x)
3954              
3955             =cut
3956              
3957             Class::Multimethods::multimethod bessel_j => qw(Math::BigNum Math::BigNum) => sub {
3958             my ($x, $n) = @_;
3959              
3960             $n = Math::GMPq::Rmpq_get_d($$n);
3961              
3962             if ($n < MIN_SI or $n > MAX_UI) {
3963             return zero();
3964             }
3965              
3966             $n = CORE::int($n);
3967             $x = _big2mpfr($x);
3968              
3969             if ($n == 0) {
3970             Math::MPFR::Rmpfr_j0($x, $x, $ROUND);
3971             }
3972             elsif ($n == 1) {
3973             Math::MPFR::Rmpfr_j1($x, $x, $ROUND);
3974             }
3975             else {
3976             Math::MPFR::Rmpfr_jn($x, $n, $x, $ROUND);
3977             }
3978              
3979             _mpfr2big($x);
3980             };
3981              
3982             Class::Multimethods::multimethod bessel_j => qw(Math::BigNum $) => sub {
3983             my ($x, $n) = @_;
3984              
3985             if (CORE::int($n) eq $n) {
3986              
3987             if ($n < MIN_SI or $n > MAX_UI) {
3988             return zero();
3989             }
3990              
3991             $x = _big2mpfr($x);
3992              
3993             if ($n == 0) {
3994             Math::MPFR::Rmpfr_j0($x, $x, $ROUND);
3995             }
3996             elsif ($n == 1) {
3997             Math::MPFR::Rmpfr_j1($x, $x, $ROUND);
3998             }
3999             else {
4000             Math::MPFR::Rmpfr_jn($x, $n, $x, $ROUND);
4001             }
4002             _mpfr2big($x);
4003             }
4004             else {
4005             $x->bessel_j(Math::BigNum->new($n));
4006             }
4007             };
4008              
4009             Class::Multimethods::multimethod bessel_j => qw(Math::BigNum *) => sub {
4010             $_[0]->bessel_j(Math::BigNum->new($_[1]));
4011             };
4012              
4013             Class::Multimethods::multimethod bessel_j => qw(Math::BigNum Math::BigNum::Inf) => \&zero;
4014             Class::Multimethods::multimethod bessel_j => qw(Math::BigNum Math::BigNum::Nan) => \&nan;
4015              
4016             =head2 bessel_y
4017              
4018             $x->bessel_y(BigNum) # => BigNum | Inf | Nan
4019             $x->bessel_y(Scalar) # => BigNum | Inf | Nan
4020              
4021             The second order Bessel function, C, where C is a signed integer. Returns Nan for negative values of C.
4022              
4023             Example:
4024              
4025             $x->bessel_y($n) # represents Y_n(x)
4026              
4027             =cut
4028              
4029             Class::Multimethods::multimethod bessel_y => qw(Math::BigNum Math::BigNum) => sub {
4030             my ($x, $n) = @_;
4031              
4032             $n = Math::GMPq::Rmpq_get_d($$n);
4033              
4034             if ($n < MIN_SI or $n > MAX_UI) {
4035              
4036             if (Math::GMPq::Rmpq_sgn($$x) < 0) {
4037             return nan();
4038             }
4039              
4040             return ($n < 0 ? inf() : ninf());
4041             }
4042              
4043             $x = _big2mpfr($x);
4044             $n = CORE::int($n);
4045              
4046             if ($n == 0) {
4047             Math::MPFR::Rmpfr_y0($x, $x, $ROUND);
4048             }
4049             elsif ($n == 1) {
4050             Math::MPFR::Rmpfr_y1($x, $x, $ROUND);
4051             }
4052             else {
4053             Math::MPFR::Rmpfr_yn($x, $n, $x, $ROUND);
4054             }
4055              
4056             _mpfr2big($x);
4057             };
4058              
4059             Class::Multimethods::multimethod bessel_y => qw(Math::BigNum $) => sub {
4060             my ($x, $n) = @_;
4061              
4062             if (CORE::int($n) eq $n) {
4063              
4064             if ($n < MIN_SI or $n > MAX_UI) {
4065              
4066             if (Math::GMPq::Rmpq_sgn($$x) < 0) {
4067             return nan();
4068             }
4069              
4070             return ($n < 0 ? inf() : ninf());
4071             }
4072              
4073             $x = _big2mpfr($x);
4074              
4075             if ($n == 0) {
4076             Math::MPFR::Rmpfr_y0($x, $x, $ROUND);
4077             }
4078             elsif ($n == 1) {
4079             Math::MPFR::Rmpfr_y1($x, $x, $ROUND);
4080             }
4081             else {
4082             Math::MPFR::Rmpfr_yn($x, $n, $x, $ROUND);
4083             }
4084             _mpfr2big($x);
4085             }
4086             else {
4087             $x->bessel_y(Math::BigNum->new($n));
4088             }
4089             };
4090              
4091             Class::Multimethods::multimethod bessel_y => qw(Math::BigNum *) => sub {
4092             $_[0]->bessel_y(Math::BigNum->new($_[1]));
4093             };
4094              
4095             Class::Multimethods::multimethod bessel_y => qw(Math::BigNum Math::BigNum::Inf) => sub {
4096             Math::GMPq::Rmpq_sgn(${$_[0]}) < 0 ? nan() : $_[1]->neg;
4097             };
4098              
4099             Class::Multimethods::multimethod bessel_y => qw(Math::BigNum Math::BigNum::Nan) => \&nan;
4100              
4101             =head2 bernreal
4102              
4103             $n->bernreal # => BigNum | Nan
4104              
4105             Returns the nth-Bernoulli number, as a floating-point approximation, with C.
4106              
4107             Returns Nan for negative values of C.
4108              
4109             =cut
4110              
4111             sub bernreal {
4112             my $n = CORE::int(Math::GMPq::Rmpq_get_d(${$_[0]}));
4113              
4114             # |B(n)| = zeta(n) * n! / 2^(n-1) / pi^n
4115              
4116             $n < 0 and return nan();
4117             $n == 0 and return one();
4118             $n == 1 and return Math::BigNum->new('1/2');
4119             $n % 2 and return zero(); # Bn = 0 for odd n>1
4120              
4121             #local $PREC = CORE::int($n*CORE::log($n)+1);
4122              
4123             my $f = Math::MPFR::Rmpfr_init2($PREC);
4124             my $p = Math::MPFR::Rmpfr_init2($PREC);
4125              
4126             Math::MPFR::Rmpfr_zeta_ui($f, $n, $ROUND); # f = zeta(n)
4127             Math::MPFR::Rmpfr_const_pi($p, $ROUND); # p = PI
4128             Math::MPFR::Rmpfr_pow_ui($p, $p, $n, $ROUND); # p = p^n
4129              
4130             my $z = Math::GMPz::Rmpz_init();
4131             Math::GMPz::Rmpz_fac_ui($z, $n); # z = n!
4132             Math::MPFR::Rmpfr_mul_z($f, $f, $z, $ROUND); # f = f * z
4133             Math::MPFR::Rmpfr_div_2exp($f, $f, $n - 1, $ROUND); # f = f / 2^(n-1)
4134              
4135             Math::MPFR::Rmpfr_div($f, $f, $p, $ROUND); # f = f/p
4136             Math::MPFR::Rmpfr_neg($f, $f, $ROUND) if $n % 4 == 0;
4137              
4138             _mpfr2big($f);
4139             }
4140              
4141             =head2 harmreal
4142              
4143             $n->harmreal # => BigNum | Nan
4144              
4145             Returns the nth-Harmonic number, as a floating-point approximation, for any real value of C >= 0.
4146              
4147             Defined as:
4148              
4149             harmreal(n) = digamma(n+1) + gamma
4150              
4151             where C is the Euler-Mascheroni constant.
4152              
4153             =cut
4154              
4155             sub harmreal {
4156             my ($n) = @_;
4157              
4158             $n = _big2mpfr($n);
4159             Math::MPFR::Rmpfr_add_ui($n, $n, 1, $ROUND);
4160             Math::MPFR::Rmpfr_digamma($n, $n, $ROUND);
4161              
4162             my $y = Math::MPFR::Rmpfr_init2($PREC);
4163             Math::MPFR::Rmpfr_const_euler($y, $ROUND);
4164             Math::MPFR::Rmpfr_add($n, $n, $y, $ROUND);
4165              
4166             _mpfr2big($n);
4167             }
4168              
4169             =head2 erf
4170              
4171             $x->erf # => BigNum
4172              
4173             The error function on C.
4174              
4175             =cut
4176              
4177             sub erf {
4178             my $r = _big2mpfr($_[0]);
4179             Math::MPFR::Rmpfr_erf($r, $r, $ROUND);
4180             _mpfr2big($r);
4181             }
4182              
4183             =head2 erfc
4184              
4185             $x->erfc # => BigNum
4186              
4187             Complementary error function on C.
4188              
4189             =cut
4190              
4191             sub erfc {
4192             my $r = _big2mpfr($_[0]);
4193             Math::MPFR::Rmpfr_erfc($r, $r, $ROUND);
4194             _mpfr2big($r);
4195             }
4196              
4197             =head2 eint
4198              
4199             $x->eint # => BigNum | Inf | Nan
4200              
4201             Exponential integral of C. Returns -Inf when C is zero, and Nan when C is negative.
4202              
4203             =cut
4204              
4205             sub eint {
4206             my $r = _big2mpfr($_[0]);
4207             Math::MPFR::Rmpfr_eint($r, $r, $ROUND);
4208             _mpfr2big($r);
4209             }
4210              
4211             =head2 li
4212              
4213             $x->li # => BigNum | Inf | Nan
4214              
4215             The logarithmic integral of C, defined as: C.
4216             Returns -Inf when C is 1, and Nan when C is less than or equal to 0.
4217              
4218             =cut
4219              
4220             sub li {
4221             my $r = _big2mpfr($_[0]);
4222             Math::MPFR::Rmpfr_log($r, $r, $ROUND);
4223             Math::MPFR::Rmpfr_eint($r, $r, $ROUND);
4224             _mpfr2big($r);
4225             }
4226              
4227             =head2 li2
4228              
4229             $x->li2 # => BigNum
4230              
4231             The dilogarithm function, defined as the integral of C<-log(1-t)/t> from 0 to C.
4232              
4233             =cut
4234              
4235             sub li2 {
4236             my $r = _big2mpfr($_[0]);
4237             Math::MPFR::Rmpfr_li2($r, $r, $ROUND);
4238             _mpfr2big($r);
4239             }
4240              
4241             ############################ INTEGER OPERATIONS ############################
4242              
4243             =head1 INTEGER OPERATIONS
4244              
4245             All the operations in this section are done with integers.
4246              
4247             =cut
4248              
4249             =head2 iadd
4250              
4251             $x->iadd(BigNum) # => BigNum
4252             $x->iadd(Scalar) # => BigNum
4253              
4254             Integer addition of C to C. Both values
4255             are truncated to integers before addition.
4256              
4257             =cut
4258              
4259             Class::Multimethods::multimethod iadd => qw(Math::BigNum Math::BigNum) => sub {
4260             my $r = _big2mpz($_[0]);
4261             Math::GMPz::Rmpz_add($r, $r, _big2mpz($_[1]));
4262             _mpz2big($r);
4263             };
4264              
4265             Class::Multimethods::multimethod iadd => qw(Math::BigNum $) => sub {
4266             my ($x, $y) = @_;
4267              
4268             if (CORE::int($y) eq $y and $y >= MIN_SI and $y <= MAX_UI) {
4269             my $r = _big2mpz($x);
4270             $y < 0
4271             ? Math::GMPz::Rmpz_sub_ui($r, $r, CORE::abs($y))
4272             : Math::GMPz::Rmpz_add_ui($r, $r, $y);
4273             _mpz2big($r);
4274             }
4275             else {
4276             Math::BigNum->new($y)->biadd($x);
4277             }
4278             };
4279              
4280             Class::Multimethods::multimethod iadd => qw(Math::BigNum *) => sub {
4281             Math::BigNum->new($_[1])->biadd($_[0]);
4282             };
4283              
4284             Class::Multimethods::multimethod iadd => qw(Math::BigNum Math::BigNum::Inf) => sub { $_[1] };
4285             Class::Multimethods::multimethod iadd => qw(Math::BigNum Math::BigNum::Nan) => \&nan;
4286              
4287             =head2 biadd
4288              
4289             $x->biadd(BigNum) # => BigNum
4290             $x->biadd(Scalar) # => BigNum
4291              
4292             Integer addition of C from C, changing C in-place.
4293             Both values are truncated to integers before addition.
4294              
4295             =cut
4296              
4297             Class::Multimethods::multimethod biadd => qw(Math::BigNum Math::BigNum) => sub {
4298             my $r = _big2mpz($_[0]);
4299             Math::GMPz::Rmpz_add($r, $r, _big2mpz($_[1]));
4300             Math::GMPq::Rmpq_set_z(${$_[0]}, $r);
4301             $_[0];
4302             };
4303              
4304             Class::Multimethods::multimethod biadd => qw(Math::BigNum $) => sub {
4305             my ($x, $y) = @_;
4306              
4307             if (CORE::int($y) eq $y and $y >= MIN_SI and $y <= MAX_UI) {
4308             my $r = _big2mpz($x);
4309             $y < 0
4310             ? Math::GMPz::Rmpz_sub_ui($r, $r, CORE::abs($y))
4311             : Math::GMPz::Rmpz_add_ui($r, $r, $y);
4312             Math::GMPq::Rmpq_set_z(${$x}, $r);
4313             $x;
4314             }
4315             else {
4316             $x->biadd(Math::BigNum->new($y));
4317             }
4318             };
4319              
4320             Class::Multimethods::multimethod biadd => qw(Math::BigNum *) => sub {
4321             $_[0]->biadd(Math::BigNum->new($_[1]));
4322             };
4323              
4324             Class::Multimethods::multimethod biadd => qw(Math::BigNum Math::BigNum::Inf) => \&_big2inf;
4325             Class::Multimethods::multimethod biadd => qw(Math::BigNum Math::BigNum::Nan) => \&bnan;
4326              
4327             =head2 isub
4328              
4329             $x->isub(BigNum) # => BigNum
4330             $x->isub(Scalar) # => BigNum
4331              
4332             Integer subtraction of C from C. Both values
4333             are truncated to integers before subtraction.
4334              
4335             =cut
4336              
4337             Class::Multimethods::multimethod isub => qw(Math::BigNum Math::BigNum) => sub {
4338             my $r = _big2mpz($_[0]);
4339             Math::GMPz::Rmpz_sub($r, $r, _big2mpz($_[1]));
4340             _mpz2big($r);
4341             };
4342              
4343             Class::Multimethods::multimethod isub => qw(Math::BigNum $) => sub {
4344             my ($x, $y) = @_;
4345              
4346             if (CORE::int($y) eq $y and $y >= MIN_SI and $y <= MAX_UI) {
4347             my $r = _big2mpz($x);
4348             $y < 0
4349             ? Math::GMPz::Rmpz_add_ui($r, $r, CORE::abs($y))
4350             : Math::GMPz::Rmpz_sub_ui($r, $r, $y);
4351             _mpz2big($r);
4352             }
4353             else {
4354             Math::BigNum->new($y)->bneg->biadd($x);
4355             }
4356             };
4357              
4358             Class::Multimethods::multimethod isub => qw(Math::BigNum *) => sub {
4359             Math::BigNum->new($_[1])->bneg->biadd($_[0]);
4360             };
4361              
4362             Class::Multimethods::multimethod isub => qw(Math::BigNum Math::BigNum::Inf) => sub { $_[1]->neg };
4363             Class::Multimethods::multimethod isub => qw(Math::BigNum Math::BigNum::Nan) => \&nan;
4364              
4365             =head2 bisub
4366              
4367             $x->bisub(BigNum) # => BigNum
4368             $x->bisub(Scalar) # => BigNum
4369              
4370             Integer subtraction of C from x, changing C in-place.
4371             Both values are truncated to integers before subtraction.
4372              
4373             =cut
4374              
4375             Class::Multimethods::multimethod bisub => qw(Math::BigNum Math::BigNum) => sub {
4376             my $r = _big2mpz($_[0]);
4377             Math::GMPz::Rmpz_sub($r, $r, _big2mpz($_[1]));
4378             Math::GMPq::Rmpq_set_z(${$_[0]}, $r);
4379             $_[0];
4380             };
4381              
4382             Class::Multimethods::multimethod bisub => qw(Math::BigNum $) => sub {
4383             my ($x, $y) = @_;
4384              
4385             if (CORE::int($y) eq $y and $y >= MIN_SI and $y <= MAX_UI) {
4386             my $r = _big2mpz($x);
4387             $y < 0
4388             ? Math::GMPz::Rmpz_add_ui($r, $r, CORE::abs($y))
4389             : Math::GMPz::Rmpz_sub_ui($r, $r, $y);
4390             Math::GMPq::Rmpq_set_z(${$x}, $r);
4391             $x;
4392             }
4393             else {
4394             $x->bisub(Math::BigNum->new($y));
4395             }
4396             };
4397              
4398             Class::Multimethods::multimethod bisub => qw(Math::BigNum *) => sub {
4399             $_[0]->bisub(Math::BigNum->new($_[1]));
4400             };
4401              
4402             Class::Multimethods::multimethod bisub => qw(Math::BigNum Math::BigNum::Inf) => \&_big2ninf;
4403             Class::Multimethods::multimethod bisub => qw(Math::BigNum Math::BigNum::Nan) => \&bnan;
4404              
4405             =head2 imul
4406              
4407             $x->imul(BigNum) # => BigNum
4408             $x->imul(Scalar) # => BigNum
4409              
4410             Integer multiplication of C by C. Both values
4411             are truncated to integers before multiplication.
4412              
4413             =cut
4414              
4415             Class::Multimethods::multimethod imul => qw(Math::BigNum Math::BigNum) => sub {
4416             my $r = _big2mpz($_[0]);
4417             Math::GMPz::Rmpz_mul($r, $r, _big2mpz($_[1]));
4418             _mpz2big($r);
4419             };
4420              
4421             Class::Multimethods::multimethod imul => qw(Math::BigNum $) => sub {
4422             my ($x, $y) = @_;
4423              
4424             if (CORE::int($y) eq $y and $y >= MIN_SI and $y <= MAX_UI) {
4425             my $r = _big2mpz($x);
4426             $y < 0
4427             ? Math::GMPz::Rmpz_mul_si($r, $r, $y)
4428             : Math::GMPz::Rmpz_mul_ui($r, $r, $y);
4429             _mpz2big($r);
4430             }
4431             else {
4432             Math::BigNum->new($y)->bimul($x);
4433             }
4434             };
4435              
4436             Class::Multimethods::multimethod imul => qw(Math::BigNum *) => sub {
4437             Math::BigNum->new($_[1])->bimul($_[0]);
4438             };
4439              
4440             Class::Multimethods::multimethod imul => qw(Math::BigNum Math::BigNum::Inf) => sub {
4441             my $sign = Math::GMPq::Rmpq_sgn(${$_[0]});
4442             $sign < 0 ? $_[1]->neg : $sign > 0 ? $_[1]->copy : nan;
4443             };
4444              
4445             Class::Multimethods::multimethod imul => qw(Math::BigNum Math::BigNum::Nan) => \&nan;
4446              
4447             =head2 bimul
4448              
4449             $x->bimul(BigNum) # => BigNum
4450             $x->bimul(Scalar) # => BigNum
4451              
4452             Integer multiplication of C by C, changing C in-place.
4453             Both values are truncated to integers before multiplication.
4454              
4455             =cut
4456              
4457             Class::Multimethods::multimethod bimul => qw(Math::BigNum Math::BigNum) => sub {
4458             my $r = _big2mpz($_[0]);
4459             Math::GMPz::Rmpz_mul($r, $r, _big2mpz($_[1]));
4460             Math::GMPq::Rmpq_set_z(${$_[0]}, $r);
4461             $_[0];
4462             };
4463              
4464             Class::Multimethods::multimethod bimul => qw(Math::BigNum $) => sub {
4465             my ($x, $y) = @_;
4466              
4467             if (CORE::int($y) eq $y and $y >= MIN_SI and $y <= MAX_UI) {
4468             my $r = _big2mpz($x);
4469             $y < 0
4470             ? Math::GMPz::Rmpz_mul_si($r, $r, $y)
4471             : Math::GMPz::Rmpz_mul_ui($r, $r, $y);
4472             Math::GMPq::Rmpq_set_z(${$x}, $r);
4473             $x;
4474             }
4475             else {
4476             $x->bimul(Math::BigNum->new($y));
4477             }
4478             };
4479              
4480             Class::Multimethods::multimethod bimul => qw(Math::BigNum *) => sub {
4481             $_[0]->bimul(Math::BigNum->new($_[1]));
4482             };
4483              
4484             Class::Multimethods::multimethod bimul => qw(Math::BigNum Math::BigNum::Inf) => sub {
4485             my ($x) = @_;
4486             my $sign = Math::GMPq::Rmpq_sgn($$x);
4487             $sign < 0 ? _big2ninf(@_) : $sign > 0 ? _big2inf(@_) : $x->bnan;
4488             };
4489              
4490             Class::Multimethods::multimethod bimul => qw(Math::BigNum Math::BigNum::Nan) => \&bnan;
4491              
4492             =head2 idiv
4493              
4494             $x->idiv(BigNum) # => BigNum | Nan | Inf
4495             $x->idiv(Scalar) # => BigNum | Nan | Inf
4496              
4497             Integer division of C by C.
4498              
4499             =cut
4500              
4501             Class::Multimethods::multimethod idiv => qw(Math::BigNum Math::BigNum) => sub {
4502             my ($x, $y) = @_;
4503              
4504             $y = _big2mpz($y);
4505             my $r = _big2mpz($x);
4506              
4507             if (!Math::GMPz::Rmpz_sgn($y)) {
4508             my $sign = Math::GMPz::Rmpz_sgn($r);
4509             return (!$sign ? nan : $sign > 0 ? inf : ninf);
4510             }
4511              
4512             Math::GMPz::Rmpz_div($r, $r, $y);
4513             _mpz2big($r);
4514             };
4515              
4516             Class::Multimethods::multimethod idiv => qw(Math::BigNum $) => sub {
4517             my ($x, $y) = @_;
4518              
4519             if (CORE::int($y) eq $y and $y >= MIN_SI and $y <= MAX_UI) {
4520              
4521             my $r = _big2mpz($x);
4522              
4523             # When `y` is zero, return +/-Inf or NaN
4524             $y || do {
4525             my $sign = Math::GMPz::Rmpz_sgn($r);
4526             return (
4527             $sign > 0 ? inf
4528             : $sign < 0 ? ninf
4529             : nan
4530             );
4531             };
4532              
4533             Math::GMPz::Rmpz_div_ui($r, $r, CORE::abs($y));
4534             Math::GMPz::Rmpz_neg($r, $r) if $y < 0;
4535             _mpz2big($r);
4536             }
4537             else {
4538             $x->idiv(Math::BigNum->new($y));
4539             }
4540             };
4541              
4542             Class::Multimethods::multimethod idiv => qw(Math::BigNum *) => sub {
4543             $_[0]->idiv(Math::BigNum->new($_[1]));
4544             };
4545              
4546             Class::Multimethods::multimethod idiv => qw(Math::BigNum Math::BigNum::Inf) => \&zero;
4547             Class::Multimethods::multimethod idiv => qw(Math::BigNum Math::BigNum::Nan) => \&nan;
4548              
4549             =head2 bidiv
4550              
4551             $x->bidiv(BigNum) # => BigNum | Nan | Inf
4552             $x->bidiv(Scalar) # => BigNum | Nan | Inf
4553              
4554             Integer division of C by C, changing C in-place.
4555              
4556             =cut
4557              
4558             Class::Multimethods::multimethod bidiv => qw(Math::BigNum Math::BigNum) => sub {
4559             my ($x, $y) = @_;
4560              
4561             $y = _big2mpz($y);
4562             my $r = _big2mpz($x);
4563              
4564             if (!Math::GMPz::Rmpz_sgn($y)) {
4565             my $sign = Math::GMPz::Rmpz_sgn($r);
4566             return
4567             $sign > 0 ? $x->binf
4568             : $sign < 0 ? $x->bninf
4569             : $x->bnan;
4570             }
4571              
4572             Math::GMPz::Rmpz_div($r, $r, $y);
4573             Math::GMPq::Rmpq_set_z($$x, $r);
4574             $x;
4575             };
4576              
4577             Class::Multimethods::multimethod bidiv => qw(Math::BigNum $) => sub {
4578             my ($x, $y) = @_;
4579              
4580             if (CORE::int($y) eq $y and $y >= MIN_SI and $y <= MAX_UI) {
4581              
4582             my $r = _big2mpz($x);
4583              
4584             # When `y` is zero, return +/-Inf or NaN
4585             $y || do {
4586             my $sign = Math::GMPz::Rmpz_sgn($r);
4587             return
4588             $sign > 0 ? $x->binf
4589             : $sign < 0 ? $x->bninf
4590             : $x->bnan;
4591             };
4592              
4593             Math::GMPz::Rmpz_div_ui($r, $r, CORE::abs($y));
4594             Math::GMPq::Rmpq_set_z($$x, $r);
4595             Math::GMPq::Rmpq_neg($$x, $$x) if $y < 0;
4596             $x;
4597             }
4598             else {
4599             $x->bidiv(Math::BigNum->new($y));
4600             }
4601             };
4602              
4603             Class::Multimethods::multimethod bidiv => qw(Math::BigNum *) => sub {
4604             $_[0]->bidiv(Math::BigNum->new($_[1]));
4605             };
4606              
4607             Class::Multimethods::multimethod bidiv => qw(Math::BigNum Math::BigNum::Inf) => \&bzero;
4608             Class::Multimethods::multimethod bidiv => qw(Math::BigNum Math::BigNum::Nan) => \&bnan;
4609              
4610             =head2 ipow
4611              
4612             $x->ipow(BigNum) # => BigNum
4613             $x->ipow(Scalar) # => BigNum
4614              
4615             Raises C to power C, truncating C and C to integers, if necessarily.
4616              
4617             =cut
4618              
4619             Class::Multimethods::multimethod ipow => qw(Math::BigNum Math::BigNum) => sub {
4620             my ($x, $y) = @_;
4621              
4622             my $pow = CORE::int(Math::GMPq::Rmpq_get_d($$y));
4623              
4624             my $z = _big2mpz($x);
4625             Math::GMPz::Rmpz_pow_ui($z, $z, CORE::abs($pow));
4626              
4627             if ($pow < 0) {
4628             return inf() if !Math::GMPz::Rmpz_sgn($z);
4629             Math::GMPz::Rmpz_tdiv_q($z, $ONE_Z, $z);
4630             }
4631              
4632             _mpz2big($z);
4633             };
4634              
4635             Class::Multimethods::multimethod ipow => qw(Math::BigNum $) => sub {
4636             my ($x, $y) = @_;
4637              
4638             if (CORE::int($y) eq $y and $y >= MIN_SI and $y <= MAX_UI) {
4639              
4640             my $z = _big2mpz($x);
4641             Math::GMPz::Rmpz_pow_ui($z, $z, CORE::abs($y));
4642              
4643             if ($y < 0) {
4644             return inf() if !Math::GMPz::Rmpz_sgn($z);
4645             Math::GMPz::Rmpz_tdiv_q($z, $ONE_Z, $z);
4646             }
4647              
4648             _mpz2big($z);
4649             }
4650             else {
4651             $x->ipow(Math::BigNum->new($y));
4652             }
4653             };
4654              
4655             Class::Multimethods::multimethod ipow => qw(Math::BigNum *) => sub {
4656             $_[0]->ipow(Math::BigNum->new($_[1]));
4657             };
4658              
4659             Class::Multimethods::multimethod ipow => qw(Math::BigNum Math::BigNum::Inf) => sub {
4660             $_[0]->int->pow($_[1]);
4661             };
4662              
4663             Class::Multimethods::multimethod ipow => qw(Math::BigNum Math::BigNum::Nan) => \&nan;
4664              
4665             =head2 bipow
4666              
4667             $x->bipow(BigNum) # => BigNum
4668             $x->bipow(Scalar) # => BigNum
4669              
4670             Raises C to power C, changing C in-place.
4671              
4672             =cut
4673              
4674             Class::Multimethods::multimethod bipow => qw(Math::BigNum Math::BigNum) => sub {
4675             my ($x, $y) = @_;
4676              
4677             my $pow = CORE::int(Math::GMPq::Rmpq_get_d($$y));
4678              
4679             my $z = Math::GMPz::Rmpz_init();
4680             Math::GMPz::Rmpz_set_q($z, $$x);
4681             Math::GMPz::Rmpz_pow_ui($z, $z, CORE::abs($pow));
4682              
4683             if ($pow < 0) {
4684             return $x->binf if !Math::GMPz::Rmpz_sgn($z);
4685             Math::GMPz::Rmpz_tdiv_q($z, $ONE_Z, $z);
4686             }
4687              
4688             Math::GMPq::Rmpq_set_z($$x, $z);
4689             return $x;
4690             };
4691              
4692             Class::Multimethods::multimethod bipow => qw(Math::BigNum $) => sub {
4693             my ($x, $y) = @_;
4694              
4695             if (CORE::int($y) eq $y and $y >= MIN_SI and $y <= MAX_UI) {
4696              
4697             my $z = Math::GMPz::Rmpz_init();
4698             Math::GMPz::Rmpz_set_q($z, $$x);
4699             Math::GMPz::Rmpz_pow_ui($z, $z, CORE::abs($y));
4700              
4701             if ($y < 0) {
4702             return $x->binf if !Math::GMPz::Rmpz_sgn($z);
4703             Math::GMPz::Rmpz_tdiv_q($z, $ONE_Z, $z);
4704             }
4705              
4706             Math::GMPq::Rmpq_set_z($$x, $z);
4707             $x;
4708             }
4709             else {
4710             $x->bipow(Math::BigNum->new($y));
4711             }
4712             };
4713              
4714             Class::Multimethods::multimethod bipow => qw(Math::BigNum *) => sub {
4715             $_[0]->bipow(Math::BigNum->new($_[1]));
4716             };
4717              
4718             Class::Multimethods::multimethod bipow => qw(Math::BigNum Math::BigNum::Inf) => sub {
4719             $_[0]->bint->bpow($_[1]);
4720             };
4721              
4722             Class::Multimethods::multimethod bipow => qw(Math::BigNum Math::BigNum::Nan) => \&bnan;
4723              
4724             =head2 isqrt
4725              
4726             $x->isqrt # => BigNum | Nan
4727              
4728             Integer square root of C. Returns Nan when C is negative.
4729              
4730             =cut
4731              
4732             sub isqrt {
4733             my $r = _big2mpz($_[0]);
4734             return nan() if Math::GMPz::Rmpz_sgn($r) < 0;
4735             Math::GMPz::Rmpz_sqrt($r, $r);
4736             _mpz2big($r);
4737             }
4738              
4739             =head2 bisqrt
4740              
4741             $x->bisqrt # => BigNum | Nan
4742              
4743             Integer square root of C, changing C in-place. Promotes C to Nan when C is negative.
4744              
4745             =cut
4746              
4747             sub bisqrt {
4748             my ($x) = @_;
4749             my $r = _big2mpz($x);
4750             return $x->bnan() if Math::GMPz::Rmpz_sgn($r) < 0;
4751             Math::GMPz::Rmpz_sqrt($r, $r);
4752             Math::GMPq::Rmpq_set_z($$x, $r);
4753             $x;
4754             }
4755              
4756             =head2 isqrtrem
4757              
4758             $x->isqrtrem # => (BigNum, BigNum) | (Nan, Nan)
4759              
4760             The integer part of the square root of C and the remainder C, which will be zero when is a perfect square.
4761              
4762             Returns (Nan,Nan) when C is negative.
4763              
4764             =cut
4765              
4766             sub isqrtrem {
4767             my ($x) = @_;
4768             $x = _big2mpz($x);
4769             Math::GMPz::Rmpz_sgn($x) < 0 && return (nan(), nan());
4770             my $r = Math::GMPz::Rmpz_init();
4771             Math::GMPz::Rmpz_sqrtrem($x, $r, $x);
4772             (_mpz2big($x), _mpz2big($r));
4773             }
4774              
4775             =head2 iroot
4776              
4777             $x->iroot(BigNum) # => BigNum | Nan
4778             $x->iroot(Scalar) # => BigNum | Nan
4779              
4780             Nth integer root of C.
4781              
4782             Returns Nan when C is negative and C is even.
4783              
4784             =cut
4785              
4786             Class::Multimethods::multimethod iroot => qw(Math::BigNum Math::BigNum) => sub {
4787             my ($x, $y) = @_;
4788              
4789             my $z = _big2mpz($x);
4790              
4791             my $root = CORE::int(Math::GMPq::Rmpq_get_d($$y));
4792              
4793             if ($root == 0) {
4794             Math::GMPz::Rmpz_sgn($z) || return zero(); # 0^Inf = 0
4795             Math::GMPz::Rmpz_cmpabs($z, $ONE_Z) == 0 and return one(); # 1^Inf = 1 ; (-1)^Inf = 1
4796             return inf();
4797             }
4798             elsif ($root < 0) {
4799             my $sign = Math::GMPz::Rmpz_sgn($z) || return inf(); # 1 / 0^k = Inf
4800             Math::GMPz::Rmpz_cmp($z, $ONE_Z) == 0 and return one(); # 1 / 1^k = 1
4801             return $sign < 0 ? nan() : zero();
4802             }
4803             elsif ($root % 2 == 0 and Math::GMPz::Rmpz_sgn($z) < 0) {
4804             return nan();
4805             }
4806              
4807             Math::GMPz::Rmpz_root($z, $z, $root);
4808             _mpz2big($z);
4809             };
4810              
4811             Class::Multimethods::multimethod iroot => qw(Math::BigNum $) => sub {
4812             my ($x, $y) = @_;
4813              
4814             if (CORE::int($y) eq $y and $y >= MIN_SI and $y <= MAX_UI) {
4815              
4816             my $z = _big2mpz($x);
4817              
4818             my $root = $y;
4819             if ($root == 0) {
4820             Math::GMPz::Rmpz_sgn($z) || return zero(); # 0^Inf = 0
4821             Math::GMPz::Rmpz_cmpabs($z, $ONE_Z) == 0 and return one(); # 1^Inf = 1 ; (-1)^Inf = 1
4822             return inf();
4823             }
4824             elsif ($root < 0) {
4825             my $sign = Math::GMPz::Rmpz_sgn($z) || return inf(); # 1 / 0^k = Inf
4826             Math::GMPz::Rmpz_cmp($z, $ONE_Z) == 0 and return one(); # 1 / 1^k = 1
4827             return $sign < 0 ? nan() : zero();
4828             }
4829             elsif ($root % 2 == 0 and Math::GMPz::Rmpz_sgn($z) < 0) {
4830             return nan();
4831             }
4832              
4833             Math::GMPz::Rmpz_root($z, $z, $root);
4834             _mpz2big($z);
4835             }
4836             else {
4837             $x->iroot(Math::BigNum->new($y));
4838             }
4839             };
4840              
4841             Class::Multimethods::multimethod iroot => qw(Math::BigNum *) => sub {
4842             $_[0]->iroot(Math::BigNum->new($_[1]));
4843             };
4844              
4845             Class::Multimethods::multimethod iroot => qw(Math::BigNum Math::BigNum::Inf) => \&one;
4846             Class::Multimethods::multimethod iroot => qw(Math::BigNum Math::BigNum::Nan) => \&nan;
4847              
4848             =head2 biroot
4849              
4850             $x->biroot(BigNum) # => BigNum | Nan
4851             $x->biroot(Scalar) # => BigNum | Nan
4852              
4853             Nth integer root of C, changing C in-place. Promotes
4854             C to Nan when C is negative and C is even.
4855              
4856             =cut
4857              
4858             Class::Multimethods::multimethod biroot => qw(Math::BigNum Math::BigNum) => sub {
4859             my ($x, $y) = @_;
4860              
4861             my $z = _big2mpz($x);
4862              
4863             my $root = CORE::int(Math::GMPq::Rmpq_get_d($$y));
4864              
4865             if ($root == 0) {
4866             Math::GMPz::Rmpz_sgn($z) || return $x->bzero(); # 0^Inf = 0
4867             Math::GMPz::Rmpz_cmpabs($z, $ONE_Z) == 0 and return $x->bone(); # 1^Inf = 1 ; (-1)^Inf = 1
4868             return $x->binf();
4869             }
4870             elsif ($root < 0) {
4871             my $sign = Math::GMPz::Rmpz_sgn($z) || return $x->binf(); # 1 / 0^k = Inf
4872             Math::GMPz::Rmpz_cmp($z, $ONE_Z) == 0 and return $x->bone(); # 1 / 1^k = 1
4873             return $sign < 0 ? $x->bnan() : $x->bzero();
4874             }
4875             elsif ($root % 2 == 0 and Math::GMPz::Rmpz_sgn($z) < 0) {
4876             return $x->bnan();
4877             }
4878              
4879             Math::GMPz::Rmpz_root($z, $z, $root);
4880             Math::GMPq::Rmpq_set_z($$x, $z);
4881             $x;
4882             };
4883              
4884             Class::Multimethods::multimethod biroot => qw(Math::BigNum $) => sub {
4885             my ($x, $y) = @_;
4886              
4887             if (CORE::int($y) eq $y and $y >= MIN_SI and $y <= MAX_UI) {
4888              
4889             my $z = _big2mpz($x);
4890              
4891             my $root = $y;
4892             if ($root == 0) {
4893             Math::GMPz::Rmpz_sgn($z) || return $x->bzero(); # 0^Inf = 0
4894             Math::GMPz::Rmpz_cmpabs($z, $ONE_Z) == 0 and return $x->bone(); # 1^Inf = 1 ; (-1)^Inf = 1
4895             return $x->binf();
4896             }
4897             elsif ($root < 0) {
4898             my $sign = Math::GMPz::Rmpz_sgn($z) || return $x->binf(); # 1 / 0^k = Inf
4899             Math::GMPz::Rmpz_cmp($z, $ONE_Z) == 0 and return $x->bone(); # 1 / 1^k = 1
4900             return $sign < 0 ? $x->bnan() : $x->bzero();
4901             }
4902             elsif ($root % 2 == 0 and Math::GMPz::Rmpz_sgn($z) < 0) {
4903             return $x->bnan();
4904             }
4905              
4906             Math::GMPz::Rmpz_root($z, $z, $root);
4907             Math::GMPq::Rmpq_set_z($$x, $z);
4908             $x;
4909             }
4910             else {
4911             $x->biroot(Math::BigNum->new($y));
4912             }
4913             };
4914              
4915             Class::Multimethods::multimethod biroot => qw(Math::BigNum *) => sub {
4916             $_[0]->biroot(Math::BigNum->new($_[1]));
4917             };
4918              
4919             Class::Multimethods::multimethod biroot => qw(Math::BigNum Math::BigNum::Inf) => \&bone;
4920             Class::Multimethods::multimethod biroot => qw(Math::BigNum Math::BigNum::Nan) => \&bnan;
4921              
4922             =head2 irootrem
4923              
4924             $x->irootrem(BigNum) # => (BigNum, BigNum) | (Nan, Nan)
4925             $x->irootrem(Scalar) # => (BigNum, BigNum) | (Nan, Nan)
4926              
4927             The nth integer part of the root of C and the remainder C.
4928              
4929             Returns (Nan,Nan) when C is negative.
4930              
4931             =cut
4932              
4933             Class::Multimethods::multimethod irootrem => qw(Math::BigNum Math::BigNum) => sub {
4934             my ($x, $y) = @_;
4935             $x = _big2mpz($x);
4936             my $root = CORE::int(Math::GMPq::Rmpq_get_d($$y));
4937              
4938             if ($root == 0) {
4939             Math::GMPz::Rmpz_sgn($x) || return (zero(), mone()); # 0^Inf = 0
4940             Math::GMPz::Rmpz_cmpabs_ui($x, 1) == 0 and return (one(), _mpz2big($x)->bdec); # 1^Inf = 1 ; (-1)^Inf = 1
4941             return (inf(), _mpz2big($x)->bdec);
4942             }
4943             elsif ($root < 0) {
4944             my $sign = Math::GMPz::Rmpz_sgn($x) || return (inf(), zero()); # 1 / 0^k = Inf
4945             Math::GMPz::Rmpz_cmp_ui($x, 1) == 0 and return (one(), zero()); # 1 / 1^k = 1
4946             return ($sign < 0 ? (nan(), nan()) : (zero(), ninf()));
4947             }
4948             elsif ($root % 2 == 0 and Math::GMPz::Rmpz_sgn($x) < 0) {
4949             return (nan(), nan());
4950             }
4951              
4952             my $r = Math::GMPz::Rmpz_init();
4953             Math::GMPz::Rmpz_rootrem($x, $r, $x, $root);
4954             (_mpz2big($x), _mpz2big($r));
4955             };
4956              
4957             Class::Multimethods::multimethod irootrem => qw(Math::BigNum $) => sub {
4958             my ($x, $y) = @_;
4959              
4960             if (CORE::int($y) eq $y and $y >= MIN_SI and $y <= MAX_UI) {
4961             $x = _big2mpz($x);
4962              
4963             if ($y == 0) {
4964             Math::GMPz::Rmpz_sgn($x) || return (zero(), mone()); # 0^Inf = 0
4965             Math::GMPz::Rmpz_cmpabs_ui($x, 1) == 0 and return (one(), _mpz2big($x)->bdec); # 1^Inf = 1 ; (-1)^Inf = 1
4966             return (inf(), _mpz2big($x)->bdec);
4967             }
4968             elsif ($y < 0) {
4969             my $sign = Math::GMPz::Rmpz_sgn($x) || return (inf(), zero()); # 1 / 0^k = Inf
4970             Math::GMPz::Rmpz_cmp_ui($x, 1) == 0 and return (one(), zero()); # 1 / 1^k = 1
4971             return ($sign < 0 ? (nan(), nan()) : (zero(), ninf()));
4972             }
4973             elsif ($y % 2 == 0 and Math::GMPz::Rmpz_sgn($x) < 0) {
4974             return (nan(), nan());
4975             }
4976              
4977             my $r = Math::GMPz::Rmpz_init();
4978             Math::GMPz::Rmpz_rootrem($x, $r, $x, $y);
4979             (_mpz2big($x), _mpz2big($r));
4980             }
4981             else {
4982             $x->irootrem(Math::BigNum->new($y));
4983             }
4984             };
4985              
4986             # Equivalent with the following definition:
4987             # irootrem(x, +/-Inf) = (1, x-1)
4988             Class::Multimethods::multimethod irootrem => qw(Math::BigNum Math::BigNum::Inf) => sub {
4989             my ($x, $y) = @_;
4990             my $root = $x->iroot($y);
4991             ($root, $x->isub($root->bipow($y)));
4992             };
4993              
4994             Class::Multimethods::multimethod irootrem => qw(Math::BigNum Math::BigNum::Nan) => sub {
4995             (nan(), nan());
4996             };
4997              
4998             Class::Multimethods::multimethod irootrem => qw(Math::BigNum *) => sub {
4999             $_[0]->irootrem(Math::BigNum->new($_[1]));
5000             };
5001              
5002             =head2 imod
5003              
5004             $x->imod(BigNum) # => BigNum | Nan
5005             $x->imod(Scalar) # => BigNum | Nan
5006              
5007             Integer remainder of C when is divided by C. If necessary, C and C
5008             are implicitly truncated to integers. Nan is returned when C is zero.
5009              
5010             =cut
5011              
5012             Class::Multimethods::multimethod imod => qw(Math::BigNum Math::BigNum) => sub {
5013             my ($x, $y) = @_;
5014              
5015             my $yz = _big2mpz($y);
5016             my $sign_y = Math::GMPz::Rmpz_sgn($yz);
5017             return nan if !$sign_y;
5018              
5019             my $r = _big2mpz($x);
5020             Math::GMPz::Rmpz_mod($r, $r, $yz);
5021             if (!Math::GMPz::Rmpz_sgn($r)) {
5022             return (zero); # return faster
5023             }
5024             elsif ($sign_y < 0) {
5025             Math::GMPz::Rmpz_add($r, $r, $yz);
5026             }
5027             _mpz2big($r);
5028             };
5029              
5030             Class::Multimethods::multimethod imod => qw(Math::BigNum $) => sub {
5031             my ($x, $y) = @_;
5032              
5033             if (CORE::int($y) eq $y and $y >= MIN_SI and $y <= MAX_UI) {
5034              
5035             $y || return nan();
5036              
5037             my $r = _big2mpz($x);
5038             my $neg_y = $y < 0;
5039             $y = CORE::abs($y) if $neg_y;
5040             Math::GMPz::Rmpz_mod_ui($r, $r, $y);
5041             if (!Math::GMPz::Rmpz_sgn($r)) {
5042             return (zero); # return faster
5043             }
5044             elsif ($neg_y) {
5045             Math::GMPz::Rmpz_sub_ui($r, $r, $y);
5046             }
5047             _mpz2big($r);
5048             }
5049             else {
5050             $x->imod(Math::BigNum->new($y));
5051             }
5052             };
5053              
5054             Class::Multimethods::multimethod imod => qw(Math::BigNum *) => sub {
5055             $_[0]->imod(Math::BigNum->new($_[1]));
5056             };
5057              
5058             Class::Multimethods::multimethod imod => qw(Math::BigNum Math::BigNum::Inf) => sub {
5059             $_[0]->copy->bimod($_[1]);
5060             };
5061              
5062             Class::Multimethods::multimethod imod => qw(Math::BigNum Math::BigNum::Nan) => \&nan;
5063              
5064             =head2 bimod
5065              
5066             $x->bimod(BigNum) # => BigNum | Nan
5067             $x->bimod(Scalar) # => BigNum | Nan
5068              
5069             Sets C to the remainder of C divided by C. If necessary, C and C
5070             are implicitly truncated to integers. Sets C to Nan when C is zero.
5071              
5072             =cut
5073              
5074             Class::Multimethods::multimethod bimod => qw(Math::BigNum Math::BigNum) => sub {
5075             my ($x, $y) = @_;
5076              
5077             my $yz = _big2mpz($y);
5078             my $sign_y = Math::GMPz::Rmpz_sgn($yz);
5079             return $x->bnan if !$sign_y;
5080              
5081             my $r = _big2mpz($x);
5082             Math::GMPz::Rmpz_mod($r, $r, $yz);
5083             if ($sign_y < 0 and Math::GMPz::Rmpz_sgn($r)) {
5084             Math::GMPz::Rmpz_add($r, $r, $yz);
5085             }
5086             Math::GMPq::Rmpq_set_z($$x, $r);
5087             $x;
5088             };
5089              
5090             Class::Multimethods::multimethod bimod => qw(Math::BigNum $) => sub {
5091             my ($x, $y) = @_;
5092              
5093             if (CORE::int($y) eq $y and $y >= MIN_SI and $y <= MAX_UI) {
5094              
5095             $y || return $x->bnan;
5096              
5097             my $r = _big2mpz($x);
5098             my $neg_y = $y < 0;
5099             $y = CORE::abs($y) if $neg_y;
5100             Math::GMPz::Rmpz_mod_ui($r, $r, $y);
5101             if ($neg_y and Math::GMPz::Rmpz_sgn($r)) {
5102             Math::GMPz::Rmpz_sub_ui($r, $r, $y);
5103             }
5104             Math::GMPq::Rmpq_set_z($$x, $r);
5105              
5106             $x;
5107             }
5108             else {
5109             $x->bimod(Math::BigNum->new($y));
5110             }
5111             };
5112              
5113             Class::Multimethods::multimethod bimod => qw(Math::BigNum *) => sub {
5114             $_[0]->bimod(Math::BigNum->new($_[1]));
5115             };
5116              
5117             # +x mod +Inf = x
5118             # +x mod -Inf = -Inf
5119             # -x mod +Inf = +Inf
5120             # -x mod -Inf = x
5121             Class::Multimethods::multimethod bimod => qw(Math::BigNum Math::BigNum::Inf) => sub {
5122             $_[0]->int->bmod($_[1]);
5123             };
5124              
5125             Class::Multimethods::multimethod bimod => qw(Math::BigNum Math::BigNum::Nan) => \&bnan;
5126              
5127             =head2 divmod
5128              
5129             $x->divmod(BigNum) # => (BigNum, BigNum) | (Nan, Nan)
5130             $x->divmod(Scalar) # => (BigNum, BigNum) | (Nan, Nan)
5131              
5132             Returns the quotient and the remainder from division of C by C,
5133             where both are integers. When C is zero, it returns two Nan values.
5134              
5135             =cut
5136              
5137             Class::Multimethods::multimethod divmod => qw(Math::BigNum Math::BigNum) => sub {
5138             my ($x, $y) = @_;
5139              
5140             my $r1 = _big2mpz($x);
5141             my $r2 = _big2mpz($y);
5142              
5143             Math::GMPz::Rmpz_sgn($$y) || return (nan, nan);
5144              
5145             Math::GMPz::Rmpz_divmod($r1, $r2, $r1, $r2);
5146             (_mpz2big($r1), _mpz2big($r2));
5147             };
5148              
5149             Class::Multimethods::multimethod divmod => qw(Math::BigNum $) => sub {
5150             my ($x, $y) = @_;
5151              
5152             if (CORE::int($y) eq $y and $y >= MIN_SI and $y <= MAX_UI) {
5153              
5154             $y || return (nan, nan);
5155              
5156             my $r1 = _big2mpz($x);
5157             my $r2 = Math::GMPz::Rmpz_init();
5158              
5159             Math::GMPz::Rmpz_divmod_ui($r1, $r2, $r1, $y);
5160             (_mpz2big($r1), _mpz2big($r2));
5161             }
5162             else {
5163             $x->divmod(Math::BigNum->new($y));
5164             }
5165             };
5166              
5167             Class::Multimethods::multimethod divmod => qw(Math::BigNum *) => sub {
5168             $_[0]->divmod(Math::BigNum->new($_[1]));
5169             };
5170              
5171             Class::Multimethods::multimethod divmod => qw(Math::BigNum Math::BigNum::Inf) => sub { (zero, $_[0]->mod($_[1])) };
5172             Class::Multimethods::multimethod divmod => qw(Math::BigNum Math::BigNum::Nan) => sub { (nan, nan) };
5173              
5174             =head1 * Number theory
5175              
5176             =cut
5177              
5178             =head2 modinv
5179              
5180             $x->modinv(BigNum) # => BigNum | Nan
5181             $x->modinv(Scalar) # => BigNum | Nan
5182              
5183             Computes the inverse of C modulo C and returns the result.
5184             If an inverse does not exists, the Nan value is returned.
5185              
5186             =cut
5187              
5188             Class::Multimethods::multimethod modinv => qw(Math::BigNum Math::BigNum) => sub {
5189             my ($x, $y) = @_;
5190             my $r = _big2mpz($x);
5191             Math::GMPz::Rmpz_invert($r, $r, _big2mpz($y)) || return nan;
5192             _mpz2big($r);
5193             };
5194              
5195             Class::Multimethods::multimethod modinv => qw(Math::BigNum $) => sub {
5196             my ($x, $y) = @_;
5197             my $z = _str2mpz($y) // return $x->modinv(Math::BigNum->new($y));
5198             my $r = _big2mpz($x);
5199             Math::GMPz::Rmpz_invert($r, $r, $z) || return nan;
5200             _mpz2big($r);
5201             };
5202              
5203             Class::Multimethods::multimethod modinv => qw(Math::BigNum *) => sub {
5204             $_[0]->modinv(Math::BigNum->new($_[1]));
5205             };
5206              
5207             Class::Multimethods::multimethod modinv => qw(Math::BigNum Math::BigNum::Inf) => \&nan;
5208             Class::Multimethods::multimethod modinv => qw(Math::BigNum Math::BigNum::Nan) => \&nan;
5209              
5210             =head2 modpow
5211              
5212             $x->modpow(BigNum, BigNum) # => BigNum | Nan
5213             $x->modpow(Scalar, Scalar) # => BigNum | Nan
5214             $x->modpow(BigNum, Scalar) # => BigNum | Nan
5215             $x->modpow(Scalar, BigNum) # => BigNum | Nan
5216              
5217             Calculates C<(x ^ y) mod z>, where all three values are integers.
5218              
5219             Returns Nan when the third argument is 0.
5220              
5221             =cut
5222              
5223             Class::Multimethods::multimethod modpow => qw(Math::BigNum Math::BigNum Math::BigNum) => sub {
5224             my ($x, $y, $z) = @_;
5225             my $mod = _big2mpz($z);
5226             Math::GMPz::Rmpz_sgn($mod) || return nan();
5227             my $r = _big2mpz($x);
5228             Math::GMPz::Rmpz_powm($r, $r, _big2mpz($y), $mod);
5229             _mpz2big($r);
5230             };
5231              
5232             Class::Multimethods::multimethod modpow => qw(Math::BigNum Math::BigNum $) => sub {
5233             my ($x, $y, $z) = @_;
5234             my $mod = _str2mpz($z) // return $x->modpow($y, Math::BigNum->new($z));
5235             Math::GMPz::Rmpz_sgn($mod) || return nan();
5236             my $r = _big2mpz($x);
5237             Math::GMPz::Rmpz_powm($r, $r, _big2mpz($y), $mod);
5238             _mpz2big($r);
5239             };
5240              
5241             Class::Multimethods::multimethod modpow => qw(Math::BigNum $ $) => sub {
5242             my ($x, $y, $z) = @_;
5243              
5244             if (CORE::int($y) eq $y and $y >= MIN_SI and $y <= MAX_UI) {
5245             my $mod = _str2mpz($z) // return $x->modpow($y, Math::BigNum->new($z));
5246             Math::GMPz::Rmpz_sgn($mod) || return nan();
5247             my $r = _big2mpz($x);
5248             if ($y >= 0) {
5249             Math::GMPz::Rmpz_powm_ui($r, $r, $y, $mod);
5250             }
5251             else {
5252             Math::GMPz::Rmpz_powm($r, $r, _str2mpz($y) // (return $x->modpow(Math::BigNum->new($y), $z)), $mod);
5253             }
5254             _mpz2big($r);
5255             }
5256             else {
5257             $x->modpow(Math::BigNum->new($y), Math::BigNum->new($z));
5258             }
5259             };
5260              
5261             Class::Multimethods::multimethod modpow => qw(Math::BigNum $ Math::BigNum) => sub {
5262             my ($x, $y, $z) = @_;
5263              
5264             my $mod = _big2mpz($z);
5265             Math::GMPz::Rmpz_sgn($mod) || return nan();
5266              
5267             if (CORE::int($y) eq $y and $y >= MIN_SI and $y <= MAX_UI) {
5268             my $r = _big2mpz($x);
5269             if ($y >= 0) {
5270             Math::GMPz::Rmpz_powm_ui($r, $r, $y, $mod);
5271             }
5272             else {
5273             Math::GMPz::Rmpz_powm($r, $r, _str2mpz($y) // (return $x->modpow(Math::BigNum->new($y), $z)), $mod);
5274             }
5275             _mpz2big($r);
5276             }
5277             else {
5278             $x->modpow(Math::BigNum->new($y), $z);
5279             }
5280             };
5281              
5282             Class::Multimethods::multimethod modpow => qw(Math::BigNum Math::BigNum *) => sub {
5283             $_[0]->modpow($_[1], Math::BigNum->new($_[2]));
5284             };
5285              
5286             Class::Multimethods::multimethod modpow => qw(Math::BigNum * Math::BigNum) => sub {
5287             $_[0]->modpow(Math::BigNum->new($_[1]), $_[2]);
5288             };
5289              
5290             Class::Multimethods::multimethod modpow => qw(Math::BigNum * *) => sub {
5291             $_[0]->modpow(Math::BigNum->new($_[1]), Math::BigNum->new($_[2]));
5292             };
5293              
5294             Class::Multimethods::multimethod modpow => qw(Math::BigNum Math::BigNum::Inf *) => sub {
5295             $_[0]->pow($_[1])->bmod($_[3]);
5296             };
5297              
5298             Class::Multimethods::multimethod modpow => qw(Math::BigNum * Math::BigNum::Inf) => sub {
5299             $_[0]->pow($_[1])->bmod($_[3]);
5300             };
5301              
5302             Class::Multimethods::multimethod modpow => qw(Math::BigNum Math::BigNum::Nan *) => \&nan;
5303             Class::Multimethods::multimethod modpow => qw(Math::BigNum * Math::BigNum::Nan) => \&nan;
5304              
5305             =head2 gcd
5306              
5307             $x->gcd(BigNum) # => BigNum
5308             $x->gcd(Scalar) # => BigNum
5309              
5310             The greatest common divisor of C and C.
5311              
5312             =cut
5313              
5314             Class::Multimethods::multimethod gcd => qw(Math::BigNum Math::BigNum) => sub {
5315             my ($x, $y) = @_;
5316             my $r = _big2mpz($x);
5317             Math::GMPz::Rmpz_gcd($r, $r, _big2mpz($y));
5318             _mpz2big($r);
5319             };
5320              
5321             Class::Multimethods::multimethod gcd => qw(Math::BigNum $) => sub {
5322             my ($x, $y) = @_;
5323             my $r = _big2mpz($x);
5324             Math::GMPz::Rmpz_gcd($r, $r, _str2mpz($y) // (return $x->gcd(Math::BigNum->new($y))));
5325             _mpz2big($r);
5326             };
5327              
5328             Class::Multimethods::multimethod gcd => qw(Math::BigNum *) => sub {
5329             $_[0]->gcd(Math::BigNum->new($_[1]));
5330             };
5331              
5332             Class::Multimethods::multimethod gcd => qw(Math::BigNum Math::BigNum::Inf) => \&nan;
5333             Class::Multimethods::multimethod gcd => qw(Math::BigNum Math::BigNum::Nan) => \&nan;
5334              
5335             =head2 lcm
5336              
5337             $x->lcd(BigNum) # => BigNum
5338             $x->lcd(Scalar) # => BigNum
5339              
5340             The least common multiple of C and C.
5341              
5342             =cut
5343              
5344             Class::Multimethods::multimethod lcm => qw(Math::BigNum Math::BigNum) => sub {
5345             my ($x, $y) = @_;
5346             my $r = _big2mpz($x);
5347             Math::GMPz::Rmpz_lcm($r, $r, _big2mpz($y));
5348             _mpz2big($r);
5349             };
5350              
5351             Class::Multimethods::multimethod lcm => qw(Math::BigNum $) => sub {
5352             my ($x, $y) = @_;
5353              
5354             my $r = _big2mpz($x);
5355              
5356             if (CORE::int($y) eq $y and $y >= MIN_SI and $y <= MAX_UI) {
5357             Math::GMPz::Rmpz_lcm_ui($r, $r, CORE::abs($y));
5358             }
5359             else {
5360             my $z = _str2mpz($y) // return $x->lcm(Math::BigNum->new($y));
5361             Math::GMPz::Rmpz_lcm($r, $r, $z);
5362             }
5363              
5364             _mpz2big($r);
5365             };
5366              
5367             Class::Multimethods::multimethod lcm => qw(Math::BigNum *) => sub {
5368             $_[0]->lcm(Math::BigNum->new($_[1]));
5369             };
5370              
5371             Class::Multimethods::multimethod lcm => qw(Math::BigNum Math::BigNum::Inf) => \&nan;
5372             Class::Multimethods::multimethod lcm => qw(Math::BigNum Math::BigNum::Nan) => \&nan;
5373              
5374             =head2 valuation
5375              
5376             $n->valuation(BigNum) # => Scalar
5377             $n->valuation(Scalar) # => Scalar
5378              
5379             Returns the number of times n is divisible by k.
5380              
5381             =cut
5382              
5383             Class::Multimethods::multimethod valuation => qw(Math::BigNum Math::BigNum) => sub {
5384             my ($x, $y) = @_;
5385              
5386             my $z = _big2mpz($y);
5387             my $sgn = Math::GMPz::Rmpz_sgn($z) || return 0;
5388             Math::GMPz::Rmpz_abs($z, $z) if $sgn < 0;
5389              
5390             my $r = _big2mpz($x);
5391             Math::GMPz::Rmpz_remove($r, $r, $z);
5392             };
5393              
5394             Class::Multimethods::multimethod valuation => qw(Math::BigNum $) => sub {
5395             my ($x, $y) = @_;
5396              
5397             my $z = _str2mpz($y) // return $x->valuation(Math::BigNum->new($y));
5398             my $sgn = Math::GMPz::Rmpz_sgn($z) || return 0;
5399             Math::GMPz::Rmpz_abs($z, $z) if $sgn < 0;
5400              
5401             my $r = _big2mpz($x);
5402             Math::GMPz::Rmpz_remove($r, $r, $z);
5403             };
5404              
5405             Class::Multimethods::multimethod valuation => qw(Math::BigNum *) => sub {
5406             $_[0]->valuation(Math::BigNum->new($_[1]));
5407             };
5408              
5409             Class::Multimethods::multimethod valuation => qw(Math::BigNum Math::BigNum::Inf) => sub { 0 };
5410             Class::Multimethods::multimethod valuation => qw(Math::BigNum Math::BigNum::Nan) => \&nan;
5411              
5412             =head2 kronecker
5413              
5414             $n->kronecker(BigNum) # => Scalar
5415             $n->kronecker(Scalar) # => Scalar
5416              
5417             Returns the Kronecker symbol I<(n|m)>, which is a generalization of the Jacobi symbol for all integers I.
5418              
5419             =cut
5420              
5421             Class::Multimethods::multimethod kronecker => qw(Math::BigNum Math::BigNum) => sub {
5422             Math::GMPz::Rmpz_kronecker(_big2mpz($_[0]), _big2mpz($_[1]));
5423             };
5424              
5425             Class::Multimethods::multimethod kronecker => qw(Math::BigNum $) => sub {
5426             my ($x, $y) = @_;
5427             if (CORE::int($y) eq $y and $y >= MIN_SI and $y <= MAX_UI) {
5428             $y >= 0
5429             ? Math::GMPz::Rmpz_kronecker_ui(_big2mpz($x), $y)
5430             : Math::GMPz::Rmpz_kronecker_si(_big2mpz($x), $y);
5431             }
5432             else {
5433             $x->kronecker(Math::BigNum->new($y));
5434             }
5435             };
5436              
5437             Class::Multimethods::multimethod kronecker => qw(Math::BigNum *) => sub {
5438             $_[0]->kronecker(Math::BigNum->new($_[1]));
5439             };
5440              
5441             Class::Multimethods::multimethod kronecker => qw(Math::BigNum Math::BigNum::Inf) => \&nan;
5442             Class::Multimethods::multimethod kronecker => qw(Math::BigNum Math::BigNum::Nan) => \&nan;
5443              
5444             =head2 is_psqr
5445              
5446             $n->is_psqr # => Bool
5447              
5448             Returns a true value when C is a perfect square.
5449             When C is not an integer, returns C<0>.
5450              
5451             =cut
5452              
5453             sub is_psqr {
5454             my ($x) = @_;
5455             Math::GMPq::Rmpq_integer_p($$x) || return 0;
5456             my $z = Math::GMPz::Rmpz_init();
5457             Math::GMPq::Rmpq_numref($z, $$x);
5458             Math::GMPz::Rmpz_perfect_square_p($z);
5459             }
5460              
5461             =head2 is_ppow
5462              
5463             $n->is_ppow # => Bool
5464              
5465             Returns a true value when C is a perfect power of some integer C.
5466             When C is not an integer, returns C<0>.
5467              
5468             =cut
5469              
5470             sub is_ppow {
5471             my ($x) = @_;
5472             Math::GMPq::Rmpq_integer_p($$x) || return 0;
5473             my $z = Math::GMPz::Rmpz_init();
5474             Math::GMPq::Rmpq_numref($z, $$x);
5475             Math::GMPz::Rmpz_perfect_power_p($z);
5476             }
5477              
5478             =head2 is_pow
5479              
5480             $n->is_pow(BigNum) # => Bool
5481             $n->is_pow(Scalar) # => Bool
5482              
5483             Return a true value when C is a perfect power of a given integer C.
5484             When C is not an integer, returns C<0>. On the other hand, when C is not an integer,
5485             it will be truncated implicitly to an integer. If C is not positive after truncation, C<0> is returned.
5486              
5487             A true value is returned iff there exists some integer I satisfying the equation: I.
5488              
5489             Example:
5490              
5491             100->is_pow(2) # true: 100 is a square (10^2)
5492             125->is_pow(3) # true: 125 is a cube ( 5^3)
5493              
5494             =cut
5495              
5496             Class::Multimethods::multimethod is_pow => qw(Math::BigNum Math::BigNum) => sub {
5497             my ($x, $y) = @_;
5498              
5499             Math::GMPq::Rmpq_integer_p($$x) || return 0;
5500             Math::GMPq::Rmpq_equal($$x, $ONE) && return 1;
5501              
5502             $x = $$x;
5503             $y = CORE::int(Math::GMPq::Rmpq_get_d($$y));
5504              
5505             # Everything is a first power
5506             $y == 1 and return 1;
5507              
5508             # Return a true value when $x=-1 and $y is odd
5509             $y % 2 and Math::GMPq::Rmpq_equal($x, $MONE) and return 1;
5510              
5511             # Don't accept a non-positive power
5512             # Also, when $x is negative and $y is even, return faster
5513             if ($y <= 0 or ($y % 2 == 0 and Math::GMPq::Rmpq_sgn($x) < 0)) {
5514             return 0;
5515             }
5516              
5517             my $z = Math::GMPz::Rmpz_init_set($x);
5518              
5519             # Optimization for perfect squares
5520             $y == 2 and return Math::GMPz::Rmpz_perfect_square_p($z);
5521              
5522             Math::GMPz::Rmpz_perfect_power_p($z) || return 0;
5523             Math::GMPz::Rmpz_root($z, $z, $y);
5524             };
5525              
5526             Class::Multimethods::multimethod is_pow => qw(Math::BigNum $) => sub {
5527             my ($x, $y) = @_;
5528              
5529             Math::GMPq::Rmpq_integer_p($$x) || return 0;
5530             Math::GMPq::Rmpq_equal($$x, $ONE) && return 1;
5531              
5532             if (CORE::int($y) eq $y and $y <= MAX_UI) {
5533              
5534             # Everything is a first power
5535             $y == 1 and return 1;
5536              
5537             # Deref $x
5538             $x = $$x;
5539              
5540             # Return a true value when $x=-1 and $y is odd
5541             $y % 2 and Math::GMPq::Rmpq_equal($x, $MONE) and return 1;
5542              
5543             # Don't accept a non-positive power
5544             # Also, when $x is negative and $y is even, return faster
5545             if ($y <= 0 or ($y % 2 == 0 and Math::GMPq::Rmpq_sgn($x) < 0)) {
5546             return 0;
5547             }
5548              
5549             my $z = Math::GMPz::Rmpz_init_set($x);
5550              
5551             # Optimization for perfect squares
5552             $y == 2 and return Math::GMPz::Rmpz_perfect_square_p($z);
5553              
5554             Math::GMPz::Rmpz_perfect_power_p($z) || return 0;
5555             Math::GMPz::Rmpz_root($z, $z, $y);
5556             }
5557             else {
5558             $x->is_pow(Math::BigNum->new($y));
5559             }
5560             };
5561              
5562             Class::Multimethods::multimethod is_pow => qw(Math::BigNum *) => sub {
5563             $_[0]->is_pow(Math::BigNum->new($_[1]));
5564             };
5565              
5566             Class::Multimethods::multimethod is_pow => qw(Math::BigNum Math::BigNum::Inf) => sub { 0 };
5567             Class::Multimethods::multimethod is_pow => qw(Math::BigNum Math::BigNum::Nan) => sub { 0 };
5568              
5569             =head2 is_prime
5570              
5571             $n->is_prime # => Scalar
5572             $x->is_prime(BigNum) # => Scalar
5573             $n->is_prime(Scalar) # => Scalar
5574              
5575             Returns 2 if C is definitely prime, 1 if C is probably prime (without
5576             being certain), or 0 if C is definitely composite. This method does some
5577             trial divisions, then some Miller-Rabin probabilistic primality tests. It
5578             also accepts an optional argument for specifying the accuracy of the test.
5579             By default, it uses an accuracy value of 20.
5580              
5581             Reasonable accuracy values are between 15 and 50.
5582              
5583             See also:
5584              
5585             https://en.wikipedia.org/wiki/Miller–Rabin_primality_test
5586             https://gmplib.org/manual/Number-Theoretic-Functions.html
5587              
5588             =cut
5589              
5590             Class::Multimethods::multimethod is_prime => qw(Math::BigNum) => sub {
5591             Math::GMPz::Rmpz_probab_prime_p(_big2mpz($_[0]), 20);
5592             };
5593              
5594             Class::Multimethods::multimethod is_prime => qw(Math::BigNum $) => sub {
5595             Math::GMPz::Rmpz_probab_prime_p(_big2mpz($_[0]), CORE::abs(CORE::int($_[1])));
5596             };
5597              
5598             Class::Multimethods::multimethod is_prime => qw(Math::BigNum Math::BigNum) => sub {
5599             Math::GMPz::Rmpz_probab_prime_p(_big2mpz($_[0]), CORE::abs(CORE::int(Math::GMPq::Rmpq_get_d(${$_[1]}))));
5600             };
5601              
5602             =head2 next_prime
5603              
5604             $n->next_prime # => BigNum
5605              
5606             Returns the next prime after C.
5607              
5608             =cut
5609              
5610             sub next_prime {
5611             my ($x) = @_;
5612             my $r = _big2mpz($x);
5613             Math::GMPz::Rmpz_nextprime($r, $r);
5614             _mpz2big($r);
5615             }
5616              
5617             =head2 fac
5618              
5619             $n->fac # => BigNum | Nan
5620              
5621             Factorial of C. Returns Nan when C is negative. (C<1*2*3*...*n>)
5622              
5623             =cut
5624              
5625             sub fac {
5626             my ($n) = @_;
5627             $n = CORE::int(Math::GMPq::Rmpq_get_d($$n));
5628             return nan() if $n < 0;
5629             my $r = Math::GMPz::Rmpz_init();
5630             Math::GMPz::Rmpz_fac_ui($r, $n);
5631             _mpz2big($r);
5632             }
5633              
5634             =head2 bfac
5635              
5636             $n->bfac # => BigNum | Nan
5637              
5638             Factorial of C, modifying C in-place.
5639              
5640             =cut
5641              
5642             sub bfac {
5643             my ($x) = @_;
5644             my $n = CORE::int(Math::GMPq::Rmpq_get_d($$x));
5645             return $x->bnan() if $n < 0;
5646             my $r = Math::GMPz::Rmpz_init();
5647             Math::GMPz::Rmpz_fac_ui($r, $n);
5648             Math::GMPq::Rmpq_set_z($$x, $r);
5649             $x;
5650             }
5651              
5652             =head2 dfac
5653              
5654             $n->dfac # => BigNum | Nan
5655              
5656             Double factorial of C. Returns Nan when C is negative.
5657              
5658             Example:
5659              
5660             7->dfac # 1*3*5*7 = 105
5661             8->dfac # 2*4*6*8 = 384
5662              
5663             =cut
5664              
5665             sub dfac {
5666             my ($n) = @_;
5667             $n = CORE::int(Math::GMPq::Rmpq_get_d($$n));
5668             return nan() if $n < 0;
5669             my $r = Math::GMPz::Rmpz_init();
5670             Math::GMPz::Rmpz_2fac_ui($r, $n);
5671             _mpz2big($r);
5672             }
5673              
5674             =head2 primorial
5675              
5676             $n->primorial # => BigNum | Nan
5677              
5678             Returns the product of all the primes less than or equal to C.
5679              
5680             =cut
5681              
5682             sub primorial {
5683             my ($n) = @_;
5684             $n = CORE::int(Math::GMPq::Rmpq_get_d($$n));
5685             return nan() if $n < 0;
5686             my $r = Math::GMPz::Rmpz_init();
5687             Math::GMPz::Rmpz_primorial_ui($r, $n);
5688             _mpz2big($r);
5689             }
5690              
5691             =head2 fib
5692              
5693             $n->fib # => BigNum | Nan
5694              
5695             The n-th Fibonacci number. Returns Nan when C is negative.
5696              
5697             Defined as:
5698              
5699             fib(0) = 0
5700             fib(1) = 1
5701             fib(n) = fib(n-1) + fib(n-2)
5702              
5703             =cut
5704              
5705             sub fib {
5706             my ($n) = @_;
5707             $n = CORE::int(Math::GMPq::Rmpq_get_d($$n));
5708             return nan() if $n < 0;
5709             my $r = Math::GMPz::Rmpz_init();
5710             Math::GMPz::Rmpz_fib_ui($r, $n);
5711             _mpz2big($r);
5712             }
5713              
5714             =head2 lucas
5715              
5716             $n->lucas # => BigNum | Nan
5717              
5718             The n-th Lucas number. Returns Nan when C is negative.
5719              
5720             Defined as:
5721              
5722             lucas(0) = 2
5723             lucas(1) = 1
5724             lucas(n) = lucas(n-1) + lucas(n-2)
5725              
5726             =cut
5727              
5728             sub lucas {
5729             my ($n) = @_;
5730             $n = CORE::int(Math::GMPq::Rmpq_get_d($$n));
5731             return nan() if $n < 0;
5732             my $r = Math::GMPz::Rmpz_init();
5733             Math::GMPz::Rmpz_lucnum_ui($r, $n);
5734             _mpz2big($r);
5735             }
5736              
5737             =head2 binomial
5738              
5739             $n->binomial(BigNum) # => BigNum
5740             $n->binomial(Scalar) # => BigNum
5741              
5742             Calculates the binomial coefficient n over k, also called the
5743             "choose" function. The result is equivalent to:
5744              
5745             ( n ) n!
5746             | | = -------
5747             ( k ) k!(n-k)!
5748              
5749             =cut
5750              
5751             Class::Multimethods::multimethod binomial => qw(Math::BigNum Math::BigNum) => sub {
5752             my ($x, $y) = @_;
5753             my $r = _big2mpz($x);
5754             $y = CORE::int(Math::GMPq::Rmpq_get_d($$y));
5755             $y >= 0
5756             ? Math::GMPz::Rmpz_bin_ui($r, $r, $y)
5757             : Math::GMPz::Rmpz_bin_si($r, $r, $y);
5758             _mpz2big($r);
5759             };
5760              
5761             Class::Multimethods::multimethod binomial => qw(Math::BigNum $) => sub {
5762             my ($x, $y) = @_;
5763             if (CORE::int($y) eq $y and $y >= MIN_SI and $y <= MAX_UI) {
5764             my $r = _big2mpz($x);
5765             $y >= 0
5766             ? Math::GMPz::Rmpz_bin_ui($r, $r, $y)
5767             : Math::GMPz::Rmpz_bin_si($r, $r, $y);
5768             _mpz2big($r);
5769             }
5770             else {
5771             $x->binomial(Math::BigNum->new($y));
5772             }
5773             };
5774              
5775             Class::Multimethods::multimethod binomial => qw(Math::BigNum *) => sub {
5776             $_[0]->binomial(Math::BigNum->new($_[1]));
5777             };
5778              
5779             Class::Multimethods::multimethod binomial => qw(Math::BigNum Math::BigNum::Inf) => \&nan;
5780             Class::Multimethods::multimethod binomial => qw(Math::BigNum Math::BigNum::Nan) => \&nan;
5781              
5782             =head1 * Bitwise operations
5783              
5784             =cut
5785              
5786             =head2 and
5787              
5788             $x->and(BigNum) # => BigNum
5789             $x->and(Scalar) # => BigNum
5790              
5791             BigNum & BigNum # => BigNum
5792             BigNum & Scalar # => BigNum
5793             Scalar & BigNum # => BigNum
5794              
5795             Integer logical-and operation.
5796              
5797             =cut
5798              
5799             Class::Multimethods::multimethod and => qw(Math::BigNum Math::BigNum) => sub {
5800             my $r = _big2mpz($_[0]);
5801             Math::GMPz::Rmpz_and($r, $r, _big2mpz($_[1]));
5802             _mpz2big($r);
5803             };
5804              
5805             Class::Multimethods::multimethod and => qw(Math::BigNum $) => sub {
5806             my $z = _str2mpz($_[1]) // return Math::BigNum->new($_[1])->band($_[0]);
5807             my $r = _big2mpz($_[0]);
5808             Math::GMPz::Rmpz_and($r, $r, $z);
5809             _mpz2big($r);
5810             };
5811              
5812             Class::Multimethods::multimethod and => qw($ Math::BigNum) => sub {
5813             my $r = _str2mpz($_[0]) // return Math::BigNum->new($_[0])->band($_[1]);
5814             Math::GMPz::Rmpz_and($r, $r, _big2mpz($_[1]));
5815             _mpz2big($r);
5816             };
5817              
5818             Class::Multimethods::multimethod and => qw(* Math::BigNum) => sub {
5819             Math::BigNum->new($_[0])->band($_[1]);
5820             };
5821              
5822             Class::Multimethods::multimethod and => qw(Math::BigNum *) => sub {
5823             Math::BigNum->new($_[1])->band($_[0]);
5824             };
5825              
5826             Class::Multimethods::multimethod and => qw(Math::BigNum Math::BigNum::Inf) => \&nan;
5827             Class::Multimethods::multimethod and => qw(Math::BigNum Math::BigNum::Nan) => \&nan;
5828              
5829             =head2 band
5830              
5831             $x->band(BigNum) # => BigNum
5832             $x->band(Scalar) # => BigNum
5833              
5834             BigNum &= BigNum # => BigNum
5835             BigNum &= Scalar # => BigNum
5836              
5837             Integer logical-and operation, changing C in-place.
5838              
5839             =cut
5840              
5841             Class::Multimethods::multimethod band => qw(Math::BigNum Math::BigNum) => sub {
5842             my $r = _big2mpz($_[0]);
5843             Math::GMPz::Rmpz_and($r, $r, _big2mpz($_[1]));
5844             Math::GMPq::Rmpq_set_z(${$_[0]}, $r);
5845             $_[0];
5846             };
5847              
5848             Class::Multimethods::multimethod band => qw(Math::BigNum $) => sub {
5849             my $z = _str2mpz($_[1]) // return $_[0]->band(Math::BigNum->new($_[1]));
5850             my $r = _big2mpz($_[0]);
5851             Math::GMPz::Rmpz_and($r, $r, $z);
5852             Math::GMPq::Rmpq_set_z(${$_[0]}, $r);
5853             $_[0];
5854             };
5855              
5856             Class::Multimethods::multimethod band => qw(Math::BigNum *) => sub {
5857             $_[0]->band(Math::BigNum->new($_[1]));
5858             };
5859              
5860             Class::Multimethods::multimethod band => qw(Math::BigNum Math::BigNum::Inf) => \&bnan;
5861             Class::Multimethods::multimethod band => qw(Math::BigNum Math::BigNum::Nan) => \&bnan;
5862              
5863             =head2 ior
5864              
5865             $x->ior(BigNum) # => BigNum
5866             $x->ior(Scalar) # => BigNum
5867              
5868             BigNum | BigNum # => BigNum
5869             BigNum | Scalar # => BigNum
5870             Scalar | BigNum # => BigNum
5871              
5872             Integer logical inclusive-or operation.
5873              
5874             =cut
5875              
5876             Class::Multimethods::multimethod ior => qw(Math::BigNum Math::BigNum) => sub {
5877             my $r = _big2mpz($_[0]);
5878             Math::GMPz::Rmpz_ior($r, $r, _big2mpz($_[1]));
5879             _mpz2big($r);
5880             };
5881              
5882             Class::Multimethods::multimethod ior => qw(Math::BigNum $) => sub {
5883             my $z = _str2mpz($_[1]) // return Math::BigNum->new($_[1])->bior($_[0]);
5884             my $r = _big2mpz($_[0]);
5885             Math::GMPz::Rmpz_ior($r, $r, $z);
5886             _mpz2big($r);
5887             };
5888              
5889             Class::Multimethods::multimethod ior => qw($ Math::BigNum) => sub {
5890             my $r = _str2mpz($_[0]) // return Math::BigNum->new($_[0])->bior($_[1]);
5891             Math::GMPz::Rmpz_ior($r, $r, _big2mpz($_[1]));
5892             _mpz2big($r);
5893             };
5894              
5895             Class::Multimethods::multimethod ior => qw(* Math::BigNum) => sub {
5896             Math::BigNum->new($_[0])->bior($_[1]);
5897             };
5898              
5899             Class::Multimethods::multimethod ior => qw(Math::BigNum *) => sub {
5900             $_[0]->ior(Math::BigNum->new($_[1]));
5901             };
5902              
5903             Class::Multimethods::multimethod ior => qw(Math::BigNum Math::BigNum::Inf) => \&nan;
5904             Class::Multimethods::multimethod ior => qw(Math::BigNum Math::BigNum::Nan) => \&nan;
5905              
5906             =head2 bior
5907              
5908             $x->bior(BigNum) # => BigNum
5909             $x->bior(Scalar) # => BigNum
5910              
5911             BigNum |= BigNum # => BigNum
5912             BigNum |= Scalar # => BigNum
5913              
5914             Integer logical inclusive-or operation, changing C in-place.
5915              
5916             =cut
5917              
5918             Class::Multimethods::multimethod bior => qw(Math::BigNum Math::BigNum) => sub {
5919             my $r = _big2mpz($_[0]);
5920             Math::GMPz::Rmpz_ior($r, $r, _big2mpz($_[1]));
5921             Math::GMPq::Rmpq_set_z(${$_[0]}, $r);
5922             $_[0];
5923             };
5924              
5925             Class::Multimethods::multimethod bior => qw(Math::BigNum $) => sub {
5926             my $z = _str2mpz($_[1]) // return $_[0]->bior(Math::BigNum->new($_[1]));
5927             my $r = _big2mpz($_[0]);
5928             Math::GMPz::Rmpz_ior($r, $r, $z);
5929             Math::GMPq::Rmpq_set_z(${$_[0]}, $r);
5930             $_[0];
5931             };
5932              
5933             Class::Multimethods::multimethod bior => qw(Math::BigNum *) => sub {
5934             $_[0]->bior(Math::BigNum->new($_[1]));
5935             };
5936              
5937             Class::Multimethods::multimethod bior => qw(Math::BigNum Math::BigNum::Inf) => \&bnan;
5938             Class::Multimethods::multimethod bior => qw(Math::BigNum Math::BigNum::Nan) => \&bnan;
5939              
5940             =head2 xor
5941              
5942             $x->xor(BigNum) # => BigNum
5943             $x->xor(Scalar) # => BigNum
5944              
5945             BigNum ^ BigNum # => BigNum
5946             BigNum ^ Scalar # => BigNum
5947             Scalar ^ BigNum # => BigNum
5948              
5949             Integer logical exclusive-or operation.
5950              
5951             =cut
5952              
5953             Class::Multimethods::multimethod xor => qw(Math::BigNum Math::BigNum) => sub {
5954             my $r = _big2mpz($_[0]);
5955             Math::GMPz::Rmpz_xor($r, $r, _big2mpz($_[1]));
5956             _mpz2big($r);
5957             };
5958              
5959             Class::Multimethods::multimethod xor => qw(Math::BigNum $) => sub {
5960             my $z = _str2mpz($_[1]) // return $_[0]->xor(Math::BigNum->new($_[1]));
5961             my $r = _big2mpz($_[0]);
5962             Math::GMPz::Rmpz_xor($r, $r, $z);
5963             _mpz2big($r);
5964             };
5965              
5966             Class::Multimethods::multimethod xor => qw($ Math::BigNum) => sub {
5967             my $r = _str2mpz($_[0]) // return Math::BigNum->new($_[0])->bxor($_[1]);
5968             Math::GMPz::Rmpz_xor($r, $r, _big2mpz($_[1]));
5969             _mpz2big($r);
5970             };
5971              
5972             Class::Multimethods::multimethod xor => qw(* Math::BigNum) => sub {
5973             Math::BigNum->new($_[0])->bxor($_[1]);
5974             };
5975              
5976             Class::Multimethods::multimethod xor => qw(Math::BigNum *) => sub {
5977             $_[0]->xor(Math::BigNum->new($_[1]));
5978             };
5979              
5980             Class::Multimethods::multimethod xor => qw(Math::BigNum Math::BigNum::Inf) => \&nan;
5981             Class::Multimethods::multimethod xor => qw(Math::BigNum Math::BigNum::Nan) => \&nan;
5982              
5983             =head2 bxor
5984              
5985             $x->bxor(BigNum) # => BigNum
5986             $x->bxor(Scalar) # => BigNum
5987              
5988             BigNum ^= BigNum # => BigNum
5989             BigNum ^= Scalar # => BigNum
5990              
5991             Integer logical exclusive-or operation, changing C in-place.
5992              
5993             =cut
5994              
5995             Class::Multimethods::multimethod bxor => qw(Math::BigNum Math::BigNum) => sub {
5996             my $r = _big2mpz($_[0]);
5997             Math::GMPz::Rmpz_xor($r, $r, _big2mpz($_[1]));
5998             Math::GMPq::Rmpq_set_z(${$_[0]}, $r);
5999             $_[0];
6000             };
6001              
6002             Class::Multimethods::multimethod bxor => qw(Math::BigNum $) => sub {
6003             my $z = _str2mpz($_[1]) // return $_[0]->bxor(Math::BigNum->new($_[1]));
6004             my $r = _big2mpz($_[0]);
6005             Math::GMPz::Rmpz_xor($r, $r, $z);
6006             Math::GMPq::Rmpq_set_z(${$_[0]}, $r);
6007             $_[0];
6008             };
6009              
6010             Class::Multimethods::multimethod bxor => qw(Math::BigNum *) => sub {
6011             $_[0]->bxor(Math::BigNum->new($_[1]));
6012             };
6013              
6014             Class::Multimethods::multimethod bxor => qw(Math::BigNum Math::BigNum::Inf) => \&bnan;
6015             Class::Multimethods::multimethod bxor => qw(Math::BigNum Math::BigNum::Nan) => \&bnan;
6016              
6017             =head2 not
6018              
6019             $x->not # => BigNum
6020             ~BigNum # => BigNum
6021              
6022             Integer logical-not operation. (The one's complement of C).
6023              
6024             =cut
6025              
6026             sub not {
6027             my $r = _big2mpz($_[0]);
6028             Math::GMPz::Rmpz_com($r, $r);
6029             _mpz2big($r);
6030             }
6031              
6032             =head2 bnot
6033              
6034             $x->bnot # => BigNum
6035              
6036             Integer logical-not operation, changing C in-place.
6037              
6038             =cut
6039              
6040             sub bnot {
6041             my $r = _big2mpz($_[0]);
6042             Math::GMPz::Rmpz_com($r, $r);
6043             Math::GMPq::Rmpq_set_z(${$_[0]}, $r);
6044             $_[0];
6045             }
6046              
6047             =head2 lsft
6048              
6049             $x->lsft(BigNum) # => BigNum
6050             $x->lsft(Scalar) # => BigNum
6051              
6052             BigNum << BigNum # => BigNum
6053             BigNum << Scalar # => BigNum
6054             Scalar << BigNum # => BigNum
6055              
6056             Integer left-shift operation. (C)
6057              
6058             =cut
6059              
6060             Class::Multimethods::multimethod lsft => qw(Math::BigNum Math::BigNum) => sub {
6061             my $r = _big2mpz($_[0]);
6062             my $i = CORE::int(Math::GMPq::Rmpq_get_d(${$_[1]}));
6063             $i < 0
6064             ? Math::GMPz::Rmpz_div_2exp($r, $r, CORE::abs($i))
6065             : Math::GMPz::Rmpz_mul_2exp($r, $r, $i);
6066             _mpz2big($r);
6067             };
6068              
6069             Class::Multimethods::multimethod lsft => qw(Math::BigNum $) => sub {
6070             my ($x, $y) = @_;
6071              
6072             if (CORE::int($y) eq $y and $y >= MIN_SI and $y <= MAX_UI) {
6073             my $r = _big2mpz($x);
6074             $y < 0
6075             ? Math::GMPz::Rmpz_div_2exp($r, $r, CORE::abs($y))
6076             : Math::GMPz::Rmpz_mul_2exp($r, $r, $y);
6077             _mpz2big($r);
6078             }
6079             else {
6080             $x->lsft(Math::BigNum->new($y));
6081             }
6082             };
6083              
6084             Class::Multimethods::multimethod lsft => qw($ Math::BigNum) => sub {
6085             my ($x, $y) = @_;
6086              
6087             my $r = _str2mpz($_[0]) // return Math::BigNum->new($x)->blsft($y);
6088             my $i = CORE::int(Math::GMPq::Rmpq_get_d(${$_[1]}));
6089             $i < 0
6090             ? Math::GMPz::Rmpz_div_2exp($r, $r, CORE::abs($i))
6091             : Math::GMPz::Rmpz_mul_2exp($r, $r, $i);
6092             _mpz2big($r);
6093             };
6094              
6095             Class::Multimethods::multimethod lsft => qw(* Math::BigNum) => sub {
6096             Math::BigNum->new($_[0])->blsft($_[1]);
6097             };
6098              
6099             Class::Multimethods::multimethod lsft => qw(Math::BigNum *) => sub {
6100             $_[0]->lsft(Math::BigNum->new($_[1]));
6101             };
6102              
6103             Class::Multimethods::multimethod lsft => qw(Math::BigNum Math::BigNum::Inf) => sub {
6104             $_[1]->is_neg || $_[0]->int->is_zero ? zero()
6105             : $_[0]->is_neg ? ninf()
6106             : inf();
6107             };
6108              
6109             Class::Multimethods::multimethod lsft => qw(Math::BigNum Math::BigNum::Nan) => \&nan;
6110              
6111             =head2 blsft
6112              
6113             $x->blsft(BigNum) # => BigNum
6114             $x->blsft(Scalar) # => BigNum
6115              
6116             BigNum <<= BigNum # => BigNum
6117             BigNum <<= Scalar # => BigNum
6118              
6119             Integer left-shift operation, changing C in-place. Promotes C to Nan when C is negative.
6120             (C)
6121              
6122             =cut
6123              
6124             Class::Multimethods::multimethod blsft => qw(Math::BigNum Math::BigNum) => sub {
6125             my $r = _big2mpz($_[0]);
6126             my $i = CORE::int(Math::GMPq::Rmpq_get_d(${$_[1]}));
6127             $i < 0
6128             ? Math::GMPz::Rmpz_div_2exp($r, $r, CORE::abs($i))
6129             : Math::GMPz::Rmpz_mul_2exp($r, $r, $i);
6130             Math::GMPq::Rmpq_set_z(${$_[0]}, $r);
6131             $_[0];
6132             };
6133              
6134             Class::Multimethods::multimethod blsft => qw(Math::BigNum $) => sub {
6135             my ($x, $y) = @_;
6136              
6137             if (CORE::int($y) eq $y and $y >= MIN_SI and $y <= MAX_UI) {
6138             my $r = _big2mpz($x);
6139             $y < 0
6140             ? Math::GMPz::Rmpz_div_2exp($r, $r, CORE::abs($y))
6141             : Math::GMPz::Rmpz_mul_2exp($r, $r, $y);
6142             Math::GMPq::Rmpq_set_z($$x, $r);
6143             $x;
6144             }
6145             else {
6146             $x->blsft(Math::BigNum->new($y));
6147             }
6148             };
6149              
6150             Class::Multimethods::multimethod blsft => qw(Math::BigNum *) => sub {
6151             $_[0]->blsft(Math::BigNum->new($_[1]));
6152             };
6153              
6154             Class::Multimethods::multimethod blsft => qw(Math::BigNum Math::BigNum::Inf) => sub {
6155             $_[1]->is_neg || $_[0]->int->is_zero ? $_[0]->bzero()
6156             : $_[0]->is_neg ? $_[0]->bninf()
6157             : $_[0]->binf();
6158             };
6159              
6160             Class::Multimethods::multimethod blsft => qw(Math::BigNum Math::BigNum::Nan) => \&bnan;
6161              
6162             =head2 rsft
6163              
6164             $x->rsft(BigNum) # => BigNum
6165             $x->rsft(Scalar) # => BigNum
6166              
6167             BigNum >> BigNum # => BigNum
6168             BigNum >> Scalar # => BigNum
6169             Scalar >> BigNum # => BigNum
6170              
6171             Integer right-shift operation. (C)
6172              
6173             =cut
6174              
6175             Class::Multimethods::multimethod rsft => qw(Math::BigNum Math::BigNum) => sub {
6176             my $r = _big2mpz($_[0]);
6177             my $i = CORE::int(Math::GMPq::Rmpq_get_d(${$_[1]}));
6178             $i < 0
6179             ? Math::GMPz::Rmpz_mul_2exp($r, $r, CORE::abs($i))
6180             : Math::GMPz::Rmpz_div_2exp($r, $r, $i);
6181             _mpz2big($r);
6182             };
6183              
6184             Class::Multimethods::multimethod rsft => qw(Math::BigNum $) => sub {
6185             my ($x, $y) = @_;
6186              
6187             if (CORE::int($y) eq $y and $y >= MIN_SI and $y <= MAX_UI) {
6188             my $r = _big2mpz($x);
6189             $y < 0
6190             ? Math::GMPz::Rmpz_mul_2exp($r, $r, CORE::abs($y))
6191             : Math::GMPz::Rmpz_div_2exp($r, $r, $y);
6192             _mpz2big($r);
6193             }
6194             else {
6195             $x->rsft(Math::BigNum->new($y));
6196             }
6197             };
6198              
6199             Class::Multimethods::multimethod rsft => qw($ Math::BigNum) => sub {
6200             my $r = _str2mpz($_[0]) // return Math::BigNum->new($_[0])->brsft($_[1]);
6201             my $i = CORE::int(Math::GMPq::Rmpq_get_d(${$_[1]}));
6202             $i < 0
6203             ? Math::GMPz::Rmpz_mul_2exp($r, $r, CORE::abs($i))
6204             : Math::GMPz::Rmpz_div_2exp($r, $r, $i);
6205             _mpz2big($r);
6206             };
6207              
6208             Class::Multimethods::multimethod rsft => qw(* Math::BigNum) => sub {
6209             Math::BigNum->new($_[0])->brsft($_[1]);
6210             };
6211              
6212             Class::Multimethods::multimethod rsft => qw(Math::BigNum *) => sub {
6213             $_[0]->rsft(Math::BigNum->new($_[1]));
6214             };
6215              
6216             Class::Multimethods::multimethod rsft => qw(Math::BigNum Math::BigNum::Inf) => sub {
6217             $_[1]->is_pos || $_[0]->int->is_zero ? zero()
6218             : $_[0]->is_neg ? ninf()
6219             : inf();
6220             };
6221              
6222             Class::Multimethods::multimethod rsft => qw(Math::BigNum Math::BigNum::Nan) => \&nan;
6223              
6224             =head2 brsft
6225              
6226             $x->brsft(BigNum) # => BigNum
6227             $x->brsft(Scalar) # => BigNum
6228              
6229             BigNum >>= BigNum # => BigNum
6230             BigNum >>= Scalar # => BigNum
6231              
6232             Integer right-shift operation, changing C in-place. (C)
6233              
6234             =cut
6235              
6236             Class::Multimethods::multimethod brsft => qw(Math::BigNum Math::BigNum) => sub {
6237             my $r = _big2mpz($_[0]);
6238             my $i = CORE::int(Math::GMPq::Rmpq_get_d(${$_[1]}));
6239             $i < 0
6240             ? Math::GMPz::Rmpz_mul_2exp($r, $r, CORE::abs($i))
6241             : Math::GMPz::Rmpz_div_2exp($r, $r, $i);
6242             Math::GMPq::Rmpq_set_z(${$_[0]}, $r);
6243             $_[0];
6244             };
6245              
6246             Class::Multimethods::multimethod brsft => qw(Math::BigNum $) => sub {
6247             my ($x, $y) = @_;
6248              
6249             if (CORE::int($y) eq $y and $y >= MIN_SI and $y <= MAX_UI) {
6250             my $r = _big2mpz($x);
6251             $y < 0
6252             ? Math::GMPz::Rmpz_mul_2exp($r, $r, CORE::abs($y))
6253             : Math::GMPz::Rmpz_div_2exp($r, $r, $y);
6254             Math::GMPq::Rmpq_set_z($$x, $r);
6255             $x;
6256             }
6257             else {
6258             $x->brsft(Math::BigNum->new($y));
6259             }
6260             };
6261              
6262             Class::Multimethods::multimethod brsft => qw(Math::BigNum *) => sub {
6263             $_[0]->brsft(Math::BigNum->new($_[1]));
6264             };
6265              
6266             Class::Multimethods::multimethod brsft => qw(Math::BigNum Math::BigNum::Inf) => sub {
6267             $_[1]->is_pos || $_[0]->int->is_zero ? $_[0]->bzero()
6268             : $_[0]->is_neg ? $_[0]->bninf()
6269             : $_[0]->binf();
6270             };
6271              
6272             Class::Multimethods::multimethod brsft => qw(Math::BigNum Math::BigNum::Nan) => \&bnan;
6273              
6274             =head2 popcount
6275              
6276             $x->popcount # => Scalar
6277              
6278             Returns the population count of C, which is the number of 1 bits in the binary representation.
6279             When C is negative, the population count of its absolute value is returned.
6280              
6281             This method is also known as the Hamming weight value.
6282              
6283             =cut
6284              
6285             sub popcount {
6286             my $z = _big2mpz($_[0]);
6287             Math::GMPz::Rmpz_neg($z, $z) if Math::GMPz::Rmpz_sgn($z) < 0;
6288             Math::GMPz::Rmpz_popcount($z);
6289             }
6290              
6291             ############################ MISCELLANEOUS ############################
6292              
6293             =head1 MISCELLANEOUS
6294              
6295             This section includes various useful methods.
6296              
6297             =cut
6298              
6299             =head2 rand
6300              
6301             $x->rand # => BigNum
6302             $x->rand(BigNum) # => BigNum
6303             $x->rand(Scalar) # => BigNum
6304              
6305             Returns a pseudorandom floating-point value. When an additional argument is provided,
6306             it returns a number between C and C, otherwise, a number between C<0> (inclusive) and
6307             C (exclusive) is returned.
6308              
6309             The PRNG behind this method is called the "Mersenne Twister". Although it generates pseudorandom
6310             numbers of very good quality, it is B cryptographically secure!
6311              
6312             Example:
6313              
6314             10->rand # a random number between 0 and 10 (exclusive)
6315             10->rand(20) # a random number between 10 and 20 (exclusive)
6316              
6317             =cut
6318              
6319             {
6320             my $srand = srand();
6321              
6322             {
6323             state $state = Math::MPFR::Rmpfr_randinit_mt_nobless();
6324             Math::MPFR::Rmpfr_randseed_ui($state, $srand);
6325              
6326             Class::Multimethods::multimethod rand => qw(Math::BigNum) => sub {
6327             my ($x) = @_;
6328              
6329             my $rand = Math::MPFR::Rmpfr_init2($PREC);
6330             Math::MPFR::Rmpfr_urandom($rand, $state, $ROUND);
6331              
6332             my $q = Math::GMPq::Rmpq_init();
6333             Math::MPFR::Rmpfr_get_q($q, $rand);
6334              
6335             Math::GMPq::Rmpq_mul($q, $q, $$x);
6336             bless \$q, __PACKAGE__;
6337             };
6338              
6339             Class::Multimethods::multimethod rand => qw(Math::BigNum Math::BigNum) => sub {
6340             my ($x, $y) = @_;
6341              
6342             my $rand = Math::MPFR::Rmpfr_init2($PREC);
6343             Math::MPFR::Rmpfr_urandom($rand, $state, $ROUND);
6344              
6345             my $q = Math::GMPq::Rmpq_init();
6346             Math::MPFR::Rmpfr_get_q($q, $rand);
6347              
6348             my $diff = Math::GMPq::Rmpq_init();
6349             Math::GMPq::Rmpq_sub($diff, $$y, $$x);
6350             Math::GMPq::Rmpq_mul($q, $q, $diff);
6351             Math::GMPq::Rmpq_add($q, $q, $$x);
6352              
6353             bless \$q, __PACKAGE__;
6354             };
6355              
6356             Class::Multimethods::multimethod rand => qw(Math::BigNum *) => sub {
6357             $_[0]->rand(Math::BigNum->new($_[1]));
6358             };
6359              
6360             Class::Multimethods::multimethod rand => qw(Math::BigNum Math::BigNum::Inf) => sub { $_[1]->copy };
6361             Class::Multimethods::multimethod rand => qw(Math::BigNum Math::BigNum::Nan) => \&nan;
6362              
6363             =head2 seed
6364              
6365             $n->seed # => BigNum
6366              
6367             Reseeds the C method with the value of C, where C can be any arbitrary large integer.
6368              
6369             Returns back the original value of C.
6370              
6371             =cut
6372              
6373             sub seed {
6374             Math::MPFR::Rmpfr_randseed($state, _big2mpz($_[0]));
6375             $_[0];
6376             }
6377             }
6378              
6379             =head2 irand
6380              
6381             $x->irand # => BigNum
6382             $x->irand(BigNum) # => BigNum
6383             $x->irand(Scalar) # => BigNum
6384              
6385             Returns a pseudorandom integer. When an additional argument is provided, it returns
6386             an integer between C and C, otherwise, an integer between C<0> (inclusive)
6387             and C (exclusive) is returned.
6388              
6389             The PRNG behind this method is called the "Mersenne Twister".
6390             Although it generates high-quality pseudorandom integers, it is B cryptographically secure!
6391              
6392             Example:
6393              
6394             10->irand # a random integer between 0 and 10 (exclusive)
6395             10->irand(20) # a random integer between 10 and 20 (exclusive)
6396              
6397             =cut
6398              
6399             {
6400             state $state = Math::GMPz::zgmp_randinit_mt_nobless();
6401             Math::GMPz::zgmp_randseed_ui($state, $srand);
6402              
6403             Class::Multimethods::multimethod irand => qw(Math::BigNum) => sub {
6404             my ($x) = @_;
6405              
6406             $x = _big2mpz($x);
6407              
6408             my $sgn = Math::GMPz::Rmpz_sgn($x) || return zero();
6409             Math::GMPz::Rmpz_urandomm($x, $state, $x, 1);
6410             Math::GMPz::Rmpz_neg($x, $x) if $sgn < 0;
6411             _mpz2big($x);
6412             };
6413              
6414             Class::Multimethods::multimethod irand => qw(Math::BigNum Math::BigNum) => sub {
6415             my ($x, $y) = @_;
6416              
6417             $x = _big2mpz($x);
6418              
6419             my $rand = _big2mpz($y);
6420             my $cmp = Math::GMPz::Rmpz_cmp($rand, $x);
6421              
6422             if ($cmp == 0) {
6423             return _mpz2big($rand);
6424             }
6425             elsif ($cmp < 0) {
6426             ($x, $rand) = ($rand, $x);
6427             }
6428              
6429             Math::GMPz::Rmpz_sub($rand, $rand, $x);
6430             Math::GMPz::Rmpz_urandomm($rand, $state, $rand, 1);
6431             Math::GMPz::Rmpz_add($rand, $rand, $x);
6432              
6433             _mpz2big($rand);
6434             };
6435              
6436             Class::Multimethods::multimethod irand => qw(Math::BigNum *) => sub {
6437             $_[0]->irand(Math::BigNum->new($_[1]));
6438             };
6439              
6440             Class::Multimethods::multimethod irand => qw(Math::BigNum Math::BigNum::Inf) => sub { $_[1]->copy };
6441             Class::Multimethods::multimethod irand => qw(Math::BigNum Math::BigNum::Nan) => \&nan;
6442              
6443             =head2 iseed
6444              
6445             $n->iseed # => BigNum
6446              
6447             Reseeds the C method with the value of C, where C can be any arbitrary large integer.
6448              
6449             Returns back the original value of C.
6450              
6451             =cut
6452              
6453             sub iseed {
6454             Math::GMPz::zgmp_randseed($state, _big2mpz($_[0]));
6455             $_[0];
6456             }
6457             }
6458             }
6459              
6460             =head2 copy
6461              
6462             $x->copy # => BigNum
6463              
6464             Returns a deep copy of C.
6465              
6466             =cut
6467              
6468             sub copy {
6469             my $r = Math::GMPq::Rmpq_init();
6470             Math::GMPq::Rmpq_set($r, ${$_[0]});
6471             bless \$r, ref($_[0]);
6472             }
6473              
6474             =head2 floor
6475              
6476             $x->floor # => BigNum
6477              
6478             Returns C if C is an integer, otherwise it rounds C towards -Infinity.
6479              
6480             Example:
6481              
6482             floor( 2.5) = 2
6483             floor(-2.5) = -3
6484              
6485             =cut
6486              
6487             sub floor {
6488             my ($x) = @_;
6489             Math::GMPq::Rmpq_integer_p($$x) && return $x->copy;
6490              
6491             if (Math::GMPq::Rmpq_sgn($$x) > 0) {
6492             my $z = Math::GMPz::Rmpz_init();
6493             Math::GMPz::Rmpz_set_q($z, $$x);
6494             _mpz2big($z);
6495             }
6496             else {
6497             my $z = Math::GMPz::Rmpz_init();
6498             Math::GMPz::Rmpz_set_q($z, $$x);
6499             Math::GMPz::Rmpz_sub_ui($z, $z, 1);
6500             _mpz2big($z);
6501             }
6502             }
6503              
6504             =head2 ceil
6505              
6506             $x->ceil # => BigNum
6507              
6508             Returns C if C is an integer, otherwise it rounds C towards +Infinity.
6509              
6510             Example:
6511              
6512             ceil( 2.5) = 3
6513             ceil(-2.5) = -2
6514              
6515             =cut
6516              
6517             sub ceil {
6518             my ($x) = @_;
6519             Math::GMPq::Rmpq_integer_p($$x) && return $x->copy;
6520              
6521             if (Math::GMPq::Rmpq_sgn($$x) > 0) {
6522             my $z = Math::GMPz::Rmpz_init();
6523             Math::GMPz::Rmpz_set_q($z, $$x);
6524             Math::GMPz::Rmpz_add_ui($z, $z, 1);
6525             _mpz2big($z);
6526             }
6527             else {
6528             my $z = Math::GMPz::Rmpz_init();
6529             Math::GMPz::Rmpz_set_q($z, $$x);
6530             _mpz2big($z);
6531             }
6532             }
6533              
6534             =head2 int
6535              
6536             $x->int # => BigNum
6537             int($x) # => BigNum
6538              
6539             Returns a truncated integer from the value of C.
6540              
6541             Example:
6542              
6543             int( 2.5) = 2
6544             int(-2.5) = -2
6545              
6546             =cut
6547              
6548             sub int {
6549             my $q = ${$_[0]};
6550             Math::GMPq::Rmpq_integer_p($q) && return $_[0]->copy;
6551             my $z = Math::GMPz::Rmpz_init();
6552             Math::GMPz::Rmpz_set_q($z, $q);
6553             _mpz2big($z);
6554             }
6555              
6556             =head2 bint
6557              
6558             $x->bint # => BigNum
6559              
6560             Truncates C to an integer in-place.
6561              
6562             =cut
6563              
6564             sub bint {
6565             my $q = ${$_[0]};
6566             Math::GMPq::Rmpq_integer_p($q) && return $_[0];
6567             my $z = Math::GMPz::Rmpz_init();
6568             Math::GMPz::Rmpz_set_q($z, $q);
6569             Math::GMPq::Rmpq_set_z($q, $z);
6570             $_[0];
6571             }
6572              
6573             =head2 float
6574              
6575             $x->float # => BigNum
6576             $x->float(Scalar) # => BigNum
6577              
6578             Returns a truncated number that fits inside number of bits specified
6579             as an argument. When no argument is specified or when the argument is
6580             undefined, the value of C<$Math::BigNum::PREC> will be used instead.
6581              
6582             =cut
6583              
6584             sub float {
6585             my ($x, $prec) = @_;
6586             my $f = Math::MPFR::Rmpfr_init2(CORE::int($prec // $PREC));
6587             Math::MPFR::Rmpfr_set_q($f, $$x, $ROUND);
6588             _mpfr2big($f);
6589             }
6590              
6591             =head2 bfloat
6592              
6593             $x->bfloat # => BigNum
6594             $x->bfloat(Scalar) # => BigNum
6595              
6596             Same as the method C, except that C is truncated in-place.
6597              
6598             =cut
6599              
6600             sub bfloat {
6601             my ($x, $prec) = @_;
6602             my $f = Math::MPFR::Rmpfr_init2(CORE::int($prec // $PREC));
6603             Math::MPFR::Rmpfr_set_q($f, $$x, $ROUND);
6604             Math::MPFR::Rmpfr_get_q($$x, $f);
6605             $x;
6606             }
6607              
6608             =head2 round
6609              
6610             $x->round(BigNum) # => BigNum
6611             $x->round(Scalar) # => BigNum
6612              
6613             Rounds C to the nth place. A negative argument rounds that many digits
6614             after the decimal point, while a positive argument rounds before the decimal
6615             point. This method uses the "round half to even" algorithm, which is the
6616             default rounding mode used in IEEE 754 computing functions and operators.
6617              
6618             =cut
6619              
6620             Class::Multimethods::multimethod round => qw(Math::BigNum $) => sub {
6621             $_[0]->copy->bround($_[1]);
6622             };
6623              
6624             Class::Multimethods::multimethod round => qw(Math::BigNum Math::BigNum) => sub {
6625             $_[0]->copy->bround(Math::GMPq::Rmpq_get_d(${$_[1]}));
6626             };
6627              
6628             =head2 bround
6629              
6630             $x->bround(BigNum) # => BigNum
6631             $x->bround(Scalar) # => BigNum
6632              
6633             Rounds C in-place to nth places.
6634              
6635             =cut
6636              
6637             Class::Multimethods::multimethod bround => qw(Math::BigNum $) => sub {
6638             my ($x, $prec) = @_;
6639              
6640             my $n = $$x;
6641             my $nth = -CORE::int($prec);
6642             my $sgn = Math::GMPq::Rmpq_sgn($n);
6643              
6644             Math::GMPq::Rmpq_abs($n, $n) if $sgn < 0;
6645              
6646             my $p = Math::GMPq::Rmpq_init();
6647             Math::GMPq::Rmpq_set_str($p, '1' . ('0' x CORE::abs($nth)), 10);
6648              
6649             if ($nth < 0) {
6650             Math::GMPq::Rmpq_div($n, $n, $p);
6651             }
6652             else {
6653             Math::GMPq::Rmpq_mul($n, $n, $p);
6654             }
6655              
6656             state $half = do {
6657             my $q = Math::GMPq::Rmpq_init_nobless();
6658             Math::GMPq::Rmpq_set_ui($q, 1, 2);
6659             $q;
6660             };
6661              
6662             Math::GMPq::Rmpq_add($n, $n, $half);
6663              
6664             my $z = Math::GMPz::Rmpz_init();
6665             Math::GMPz::Rmpz_set_q($z, $n);
6666              
6667             if (Math::GMPz::Rmpz_odd_p($z) and Math::GMPq::Rmpq_integer_p($n)) {
6668             Math::GMPz::Rmpz_sub_ui($z, $z, 1);
6669             }
6670              
6671             Math::GMPq::Rmpq_set_z($n, $z);
6672              
6673             if ($nth < 0) {
6674             Math::GMPq::Rmpq_mul($n, $n, $p);
6675             }
6676             else {
6677             Math::GMPq::Rmpq_div($n, $n, $p);
6678             }
6679              
6680             if ($sgn < 0) {
6681             Math::GMPq::Rmpq_neg($n, $n);
6682             }
6683              
6684             $x;
6685             };
6686              
6687             Class::Multimethods::multimethod bround => qw(Math::BigNum Math::BigNum) => sub {
6688             $_[0]->bround(Math::GMPq::Rmpq_get_d(${$_[1]}));
6689             };
6690              
6691             =head2 neg
6692              
6693             $x->neg # => BigNum
6694             -$x # => BigNum
6695              
6696             Negative value of C.
6697              
6698             =cut
6699              
6700             sub neg {
6701             my ($x) = @_;
6702             my $r = Math::GMPq::Rmpq_init();
6703             Math::GMPq::Rmpq_neg($r, $$x);
6704             bless \$r, __PACKAGE__;
6705             }
6706              
6707             =head2 bneg
6708              
6709             $x->bneg # => BigNum
6710              
6711             Negative value of C, changing C in-place.
6712              
6713             =cut
6714              
6715             sub bneg {
6716             Math::GMPq::Rmpq_neg(${$_[0]}, ${$_[0]});
6717             $_[0];
6718             }
6719              
6720             =head2 abs
6721              
6722             $x->abs # => BigNum
6723             abs($x) # => BigNum
6724              
6725             Absolute value of C.
6726              
6727             Example:
6728              
6729             abs(-42) = 42
6730             abs( 42) = 42
6731              
6732             =cut
6733              
6734             sub abs {
6735             my ($x) = @_;
6736             my $r = Math::GMPq::Rmpq_init();
6737             Math::GMPq::Rmpq_abs($r, $$x);
6738             bless \$r, __PACKAGE__;
6739             }
6740              
6741             =head2 babs
6742              
6743             $x->babs # => BigNum
6744              
6745             Absolute value of C, changing C in-place.
6746              
6747             =cut
6748              
6749             sub babs {
6750             Math::GMPq::Rmpq_abs(${$_[0]}, ${$_[0]});
6751             $_[0];
6752             }
6753              
6754             =head2 inc
6755              
6756             $x->inc # => BigNum
6757              
6758             Returns C.
6759              
6760             =cut
6761              
6762             sub inc {
6763             my ($x) = @_;
6764             my $r = Math::GMPq::Rmpq_init();
6765             Math::GMPq::Rmpq_add($r, $$x, $ONE);
6766             bless \$r, __PACKAGE__;
6767             }
6768              
6769             =head2 binc
6770              
6771             $x->binc # => BigNum
6772             ++$x # => BigNum
6773             $x++ # => BigNum
6774              
6775             Increments C in-place by 1.
6776              
6777             =cut
6778              
6779             sub binc {
6780             my ($x) = @_;
6781             Math::GMPq::Rmpq_add($$x, $$x, $ONE);
6782             $x;
6783             }
6784              
6785             =head2 dec
6786              
6787             $x->dec # => BigNum
6788              
6789             Returns C.
6790              
6791             =cut
6792              
6793             sub dec {
6794             my ($x) = @_;
6795             my $r = Math::GMPq::Rmpq_init();
6796             Math::GMPq::Rmpq_sub($r, $$x, $ONE);
6797             bless \$r, __PACKAGE__;
6798             }
6799              
6800             =head2 bdec
6801              
6802             $x->bdec # => BigNum
6803             --$x # => BigNum
6804             $x-- # => BigNum
6805              
6806             Decrements C in-place by 1.
6807              
6808             =cut
6809              
6810             sub bdec {
6811             my ($x) = @_;
6812             Math::GMPq::Rmpq_sub($$x, $$x, $ONE);
6813             $x;
6814             }
6815              
6816             =head1 * Introspection
6817              
6818             =cut
6819              
6820             =head2 is_zero
6821              
6822             $x->is_zero # => Bool
6823              
6824             Returns a true value when C is 0.
6825              
6826             =cut
6827              
6828             sub is_zero {
6829             !Math::GMPq::Rmpq_sgn(${$_[0]});
6830             }
6831              
6832             =head2 is_one
6833              
6834             $x->is_one # => Bool
6835              
6836             Returns a true value when C is +1.
6837              
6838             =cut
6839              
6840             sub is_one {
6841             Math::GMPq::Rmpq_equal(${$_[0]}, $ONE);
6842             }
6843              
6844             =head2 is_mone
6845              
6846             $x->is_mone # => Bool
6847              
6848             Returns a true value when C is -1.
6849              
6850             =cut
6851              
6852             sub is_mone {
6853             Math::GMPq::Rmpq_equal(${$_[0]}, $MONE);
6854             }
6855              
6856             =head2 is_pos
6857              
6858             $x->is_pos # => Bool
6859              
6860             Returns a true value when C is greater than zero.
6861              
6862             =cut
6863              
6864             sub is_pos {
6865             Math::GMPq::Rmpq_sgn(${$_[0]}) > 0;
6866             }
6867              
6868             =head2 is_neg
6869              
6870             $x->is_neg # => Bool
6871              
6872             Returns a true value when C is less than zero.
6873              
6874             =cut
6875              
6876             sub is_neg {
6877             Math::GMPq::Rmpq_sgn(${$_[0]}) < 0;
6878             }
6879              
6880             =head2 is_int
6881              
6882             $x->is_int # => Bool
6883              
6884             Returns a true value when C is an integer.
6885              
6886             =cut
6887              
6888             sub is_int {
6889             Math::GMPq::Rmpq_integer_p(${$_[0]});
6890             }
6891              
6892             =head2 is_real
6893              
6894             $x->is_real # => Bool
6895              
6896             Always returns a true value when invoked on a Math::BigNum object.
6897              
6898             =cut
6899              
6900             sub is_real { 1 }
6901              
6902             =head2 is_inf
6903              
6904             $x->is_inf # => Bool
6905              
6906             Always returns a false value when invoked on a Math::BigNum object.
6907              
6908             =cut
6909              
6910             sub is_inf { 0 }
6911              
6912             =head2 is_nan
6913              
6914             $x->is_nan # => Bool
6915              
6916             Always returns a false value when invoked on a Math::BigNum object.
6917              
6918             =cut
6919              
6920             sub is_nan { 0 }
6921              
6922             =head2 is_ninf
6923              
6924             $x->is_ninf # => Bool
6925              
6926             Always returns a false value when invoked on a Math::BigNum object.
6927              
6928             =cut
6929              
6930             sub is_ninf { 0 }
6931              
6932             =head2 is_odd
6933              
6934             $x->is_odd # => Bool
6935              
6936             Returns a true value when C is NOT divisible by 2. Returns C<0> if C is NOT an integer.
6937              
6938             =cut
6939              
6940             sub is_odd {
6941             my ($x) = @_;
6942             Math::GMPq::Rmpq_integer_p($$x) || return 0;
6943             my $nz = Math::GMPz::Rmpz_init();
6944             Math::GMPq::Rmpq_numref($nz, $$x);
6945             Math::GMPz::Rmpz_odd_p($nz);
6946             }
6947              
6948             =head2 is_even
6949              
6950             $x->is_even # => Bool
6951              
6952             Returns a true value when C is divisible by 2. Returns C<0> if C is NOT an integer.
6953              
6954             =cut
6955              
6956             sub is_even {
6957             my ($x) = @_;
6958             Math::GMPq::Rmpq_integer_p($$x) || return 0;
6959             my $nz = Math::GMPz::Rmpz_init();
6960             Math::GMPq::Rmpq_numref($nz, $$x);
6961             Math::GMPz::Rmpz_even_p($nz);
6962             }
6963              
6964             =head2 is_div
6965              
6966             $x->is_div(BigNum) # => Bool
6967             $x->is_div(Scalar) # => Bool
6968              
6969             Returns a true value if C is divisible by C (i.e. when the
6970             result of division of C by C is an integer). False otherwise.
6971              
6972             Example:
6973              
6974             is_div(15, 3) = true
6975             is_div(15, 4) = false
6976              
6977             It is also defined for rational numbers, returning a true value when the quotient of division is an integer:
6978              
6979             is_div(17, 3.4) = true # because: 17/3.4 = 5
6980              
6981             This method is very efficient when the first argument is an integer and the second argument is a I integer.
6982              
6983             =cut
6984              
6985             Class::Multimethods::multimethod is_div => qw(Math::BigNum Math::BigNum) => sub {
6986             my ($x, $y) = @_;
6987              
6988             Math::GMPq::Rmpq_sgn($$y) || return 0;
6989              
6990             #<<<
6991             #---------------------------------------------------------------------------------
6992             ## Optimization for integers, but it turned out to be slower for small integers...
6993             #---------------------------------------------------------------------------------
6994             #~ if (Math::GMPq::Rmpq_integer_p($$y) and Math::GMPq::Rmpq_integer_p($$x)) {
6995             #~ my $d = CORE::int(CORE::abs(Math::GMPq::Rmpq_get_d($$y)));
6996             #~ if ($d <= MAX_UI) {
6997             #~ Math::GMPz::Rmpz_set_q((my $z = Math::GMPz::Rmpz_init()), $$x);
6998             #~ return Math::GMPz::Rmpz_divisible_ui_p($z, $d);
6999             #~ }
7000             #~ else {
7001             #~ return Math::GMPz::Rmpz_divisible_p(_int2mpz($x), _int2mpz($y));
7002             #~ }
7003             #~ }
7004             #>>>
7005              
7006             my $q = Math::GMPq::Rmpq_init();
7007             Math::GMPq::Rmpq_div($q, $$x, $$y);
7008             Math::GMPq::Rmpq_integer_p($q);
7009             };
7010              
7011             Class::Multimethods::multimethod is_div => qw(Math::BigNum $) => sub {
7012             my ($x, $y) = @_;
7013              
7014             $y || return 0;
7015              
7016             # Use a faster method when both $x and $y are integers
7017             if (CORE::int($y) eq $y and CORE::abs($y) <= MAX_UI and Math::GMPq::Rmpq_integer_p($$x)) {
7018             Math::GMPz::Rmpz_divisible_ui_p(_int2mpz($x), CORE::abs($y));
7019             }
7020              
7021             # Otherwise, do the division and check the result
7022             else {
7023             my $q = _str2mpq($y) // return $x->is_div(Math::BigNum->new($y));
7024             Math::GMPq::Rmpq_div($q, $$x, $q);
7025             Math::GMPq::Rmpq_integer_p($q);
7026             }
7027             };
7028              
7029             Class::Multimethods::multimethod is_div => qw(Math::BigNum *) => sub {
7030             $_[0]->is_div(Math::BigNum->new($_[1]));
7031             };
7032              
7033             Class::Multimethods::multimethod is_div => qw(Math::BigNum Math::BigNum::Inf) => sub { 0 };
7034             Class::Multimethods::multimethod is_div => qw(Math::BigNum Math::BigNum::Nan) => sub { 0 };
7035              
7036             =head2 sign
7037              
7038             $x->sign # => Scalar
7039              
7040             Returns C<-1> when C is negative, C<1> when C is positive, and C<0> when C is zero.
7041              
7042             =cut
7043              
7044             sub sign {
7045             Math::GMPq::Rmpq_sgn(${$_[0]});
7046             }
7047              
7048             =head2 length
7049              
7050             $x->length # => Scalar
7051              
7052             Returns the number of digits of C in base 10 before the decimal point.
7053              
7054             For C, it returns C<4>.
7055              
7056             =cut
7057              
7058             sub length {
7059             my $z = Math::GMPz::Rmpz_init();
7060             Math::GMPz::Rmpz_set_q($z, ${$_[0]});
7061             Math::GMPz::Rmpz_abs($z, $z);
7062             CORE::length(Math::GMPz::Rmpz_get_str($z, 10));
7063             }
7064              
7065             =head1 * Conversions
7066              
7067             =cut
7068              
7069             =head2 stringify
7070              
7071             $x->stringify # => Scalar
7072              
7073             Returns a string representing the value of C, either as a base-10 integer,
7074             or a decimal expansion.
7075              
7076             Example:
7077              
7078             stringify(1/2) = "0.5"
7079             stringify(100) = "100"
7080              
7081             =cut
7082              
7083             sub stringify {
7084             my $x = ${$_[0]};
7085             Math::GMPq::Rmpq_integer_p($x)
7086             ? Math::GMPq::Rmpq_get_str($x, 10)
7087             : do {
7088             $PREC = CORE::int($PREC) if ref($PREC);
7089              
7090             my $prec = CORE::int($PREC / 4);
7091             my $sgn = Math::GMPq::Rmpq_sgn($x);
7092              
7093             my $n = Math::GMPq::Rmpq_init();
7094             Math::GMPq::Rmpq_set($n, $x);
7095             Math::GMPq::Rmpq_abs($n, $n) if $sgn < 0;
7096              
7097             my $p = Math::GMPq::Rmpq_init();
7098             Math::GMPq::Rmpq_set_str($p, '1' . ('0' x CORE::abs($prec)), 10);
7099              
7100             if ($prec < 0) {
7101             Math::GMPq::Rmpq_div($n, $n, $p);
7102             }
7103             else {
7104             Math::GMPq::Rmpq_mul($n, $n, $p);
7105             }
7106              
7107             state $half = do {
7108             my $q = Math::GMPq::Rmpq_init_nobless();
7109             Math::GMPq::Rmpq_set_ui($q, 1, 2);
7110             $q;
7111             };
7112              
7113             my $z = Math::GMPz::Rmpz_init();
7114             Math::GMPq::Rmpq_add($n, $n, $half);
7115             Math::GMPz::Rmpz_set_q($z, $n);
7116              
7117             # Too much rounding... Give up and return an MPFR stringified number.
7118             !Math::GMPz::Rmpz_sgn($z) && $PREC >= 2 && do {
7119             my $mpfr = Math::MPFR::Rmpfr_init2($PREC);
7120             Math::MPFR::Rmpfr_set_q($mpfr, $x, $ROUND);
7121             return Math::MPFR::Rmpfr_get_str($mpfr, 10, $prec, $ROUND);
7122             };
7123              
7124             if (Math::GMPz::Rmpz_odd_p($z) and Math::GMPq::Rmpq_integer_p($n)) {
7125             Math::GMPz::Rmpz_sub_ui($z, $z, 1);
7126             }
7127              
7128             Math::GMPq::Rmpq_set_z($n, $z);
7129              
7130             if ($prec < 0) {
7131             Math::GMPq::Rmpq_mul($n, $n, $p);
7132             }
7133             else {
7134             Math::GMPq::Rmpq_div($n, $n, $p);
7135             }
7136              
7137             my $num = Math::GMPz::Rmpz_init();
7138             my $den = Math::GMPz::Rmpz_init();
7139              
7140             Math::GMPq::Rmpq_numref($num, $n);
7141             Math::GMPq::Rmpq_denref($den, $n);
7142              
7143             my @r;
7144             while (1) {
7145             Math::GMPz::Rmpz_div($z, $num, $den);
7146             push @r, Math::GMPz::Rmpz_get_str($z, 10);
7147              
7148             Math::GMPz::Rmpz_mul($z, $z, $den);
7149             Math::GMPz::Rmpz_sub($num, $num, $z);
7150             last if !Math::GMPz::Rmpz_sgn($num);
7151              
7152             my $s = -1;
7153             while (Math::GMPz::Rmpz_cmp($den, $num) > 0) {
7154             Math::GMPz::Rmpz_mul_ui($num, $num, 10);
7155             ++$s;
7156             }
7157              
7158             push(@r, '0' x $s) if ($s > 0);
7159             }
7160              
7161             ($sgn < 0 ? "-" : '') . shift(@r) . (('.' . join('', @r)) =~ s/0+\z//r =~ s/\.\z//r);
7162             }
7163             }
7164              
7165             =head2 numify
7166              
7167             $x->numify # => Scalar
7168              
7169             Returns a Perl numerical scalar with the value of C, truncated if needed.
7170              
7171             =cut
7172              
7173             sub numify {
7174             Math::GMPq::Rmpq_get_d(${$_[0]});
7175             }
7176              
7177             =head2 boolify
7178              
7179             $x->boolify # => Bool
7180              
7181             Returns a true value when the number is not zero. False otherwise.
7182              
7183             =cut
7184              
7185             sub boolify {
7186             !!Math::GMPq::Rmpq_sgn(${$_[0]});
7187             }
7188              
7189             =head2 as_frac
7190              
7191             $x->as_frac # => Scalar
7192              
7193             Returns a string representing the number as a base-10 fraction.
7194              
7195             Example:
7196              
7197             as_frac(3.5) = "7/2"
7198             as_frac(3.0) = "3/1"
7199              
7200             =cut
7201              
7202             sub as_frac {
7203             my $rat = Math::GMPq::Rmpq_get_str(${$_[0]}, 10);
7204             index($rat, '/') == -1 ? "$rat/1" : $rat;
7205             }
7206              
7207             =head2 as_rat
7208              
7209             $x->as_rat # => Scalar
7210              
7211             Almost the same as C, except that integers are returned as they are,
7212             without adding a denominator of 1.
7213              
7214             Example:
7215              
7216             as_rat(3.5) = "7/2"
7217             as_rat(3.0) = "3"
7218              
7219             =cut
7220              
7221             sub as_rat {
7222             Math::GMPq::Rmpq_get_str(${$_[0]}, 10);
7223             }
7224              
7225             =head2 as_float
7226              
7227             $x->as_float # => Scalar
7228             $x->as_float(Scalar) # => Scalar
7229             $x->as_float(BigNum) # => Scalar
7230              
7231             Returns the self-number as a floating-point scalar. The method also accepts
7232             an optional argument for precision after the decimal point. When no argument
7233             is provided, it uses the default precision.
7234              
7235             Example:
7236              
7237             as_float(1/3, 4) = "0.3333"
7238              
7239             If the self number is an integer, it will be returned as it is.
7240              
7241             =cut
7242              
7243             Class::Multimethods::multimethod as_float => qw(Math::BigNum) => sub {
7244             $_[0]->stringify;
7245             };
7246              
7247             Class::Multimethods::multimethod as_float => qw(Math::BigNum $) => sub {
7248             local $Math::BigNum::PREC = 4 * $_[1];
7249             $_[0]->stringify;
7250             };
7251              
7252             Class::Multimethods::multimethod as_float => qw(Math::BigNum Math::BigNum) => sub {
7253             local $Math::BigNum::PREC = 4 * Math::GMPq::Rmpq_get_d(${$_[1]});
7254             $_[0]->stringify;
7255             };
7256              
7257             =head2 as_int
7258              
7259             $x->as_int # => Scalar
7260             $x->as_int(Scalar) # => Scalar
7261             $x->as_int(BigNum) # => Scalar
7262              
7263             Returns the self-number as an integer in a given base. When the base is omitted, it
7264             defaults to 10.
7265              
7266             Example:
7267              
7268             as_int(255) = "255"
7269             as_int(255, 16) = "ff"
7270              
7271             =cut
7272              
7273             Class::Multimethods::multimethod as_int => qw(Math::BigNum) => sub {
7274             my $z = Math::GMPz::Rmpz_init();
7275             Math::GMPz::Rmpz_set_q($z, ${$_[0]});
7276             Math::GMPz::Rmpz_get_str($z, 10);
7277             };
7278              
7279             Class::Multimethods::multimethod as_int => qw(Math::BigNum $) => sub {
7280             my $z = Math::GMPz::Rmpz_init();
7281             Math::GMPz::Rmpz_set_q($z, ${$_[0]});
7282              
7283             my $base = CORE::int($_[1]);
7284             if ($base < 2 or $base > 36) {
7285             require Carp;
7286             Carp::croak("base must be between 2 and 36, got $base");
7287             }
7288              
7289             Math::GMPz::Rmpz_get_str($z, $base);
7290             };
7291              
7292             Class::Multimethods::multimethod as_int => qw(Math::BigNum Math::BigNum) => sub {
7293             $_[0]->as_int(Math::GMPq::Rmpq_get_d(${$_[1]}));
7294             };
7295              
7296             =head2 as_bin
7297              
7298             $x->as_bin # => Scalar
7299              
7300             Returns a string representing the value of C in binary.
7301              
7302             Example:
7303              
7304             as_bin(42) = "101010"
7305              
7306             =cut
7307              
7308             sub as_bin {
7309             my $z = Math::GMPz::Rmpz_init();
7310             Math::GMPz::Rmpz_set_q($z, ${$_[0]});
7311             Math::GMPz::Rmpz_get_str($z, 2);
7312             }
7313              
7314             =head2 as_oct
7315              
7316             $x->as_oct # => Scalar
7317              
7318             Returns a string representing the value of C in octal.
7319              
7320             Example:
7321              
7322             as_oct(42) = "52"
7323              
7324             =cut
7325              
7326             sub as_oct {
7327             my $z = Math::GMPz::Rmpz_init();
7328             Math::GMPz::Rmpz_set_q($z, ${$_[0]});
7329             Math::GMPz::Rmpz_get_str($z, 8);
7330             }
7331              
7332             =head2 as_hex
7333              
7334             $x->as_hex # => Scalar
7335              
7336             Returns a string representing the value of C in hexadecimal.
7337              
7338             Example:
7339              
7340             as_hex(42) = "2a"
7341              
7342             =cut
7343              
7344             sub as_hex {
7345             my $z = Math::GMPz::Rmpz_init();
7346             Math::GMPz::Rmpz_set_q($z, ${$_[0]});
7347             Math::GMPz::Rmpz_get_str($z, 16);
7348             }
7349              
7350             =head2 in_base
7351              
7352             $x->in_base(Scalar) # => Scalar
7353              
7354             Returns a string with the value of C in a given base,
7355             where the base can range from 2 to 36 inclusive. If C
7356             is not an integer, the result is returned in rationalized
7357             form.
7358              
7359             Example:
7360              
7361             in_base(42, 3) = "1120"
7362             in_base(12.34, 36) = "h5/1e"
7363              
7364             =cut
7365              
7366             Class::Multimethods::multimethod in_base => qw(Math::BigNum $) => sub {
7367             my ($x, $y) = @_;
7368              
7369             if ($y < 2 or $y > 36) {
7370             require Carp;
7371             Carp::croak("base must be between 2 and 36, got $y");
7372             }
7373              
7374             Math::GMPq::Rmpq_get_str($$x, $y);
7375             };
7376              
7377             Class::Multimethods::multimethod in_base => qw(Math::BigNum Math::BigNum) => sub {
7378             $_[0]->in_base(CORE::int(Math::GMPq::Rmpq_get_d(${$_[1]})));
7379             };
7380              
7381             =head2 deg2rad
7382              
7383             $x->deg2rad # => BigNum
7384              
7385             Returns the value of C converted from degrees to radians.
7386              
7387             Example:
7388              
7389             deg2rad(180) = pi
7390              
7391             =cut
7392              
7393             sub deg2rad {
7394             Math::MPFR::Rmpfr_const_pi((my $pi = Math::MPFR::Rmpfr_init2($PREC)), $ROUND);
7395             Math::MPFR::Rmpfr_div_ui((my $fr = Math::MPFR::Rmpfr_init2($PREC)), $pi, 180, $ROUND);
7396              
7397             ## Version 1
7398             #~ my $q = Math::GMPq::Rmpq_init();
7399             #~ Math::MPFR::Rmpfr_get_q($q, $fr);
7400             #~ Math::GMPq::Rmpq_mul($q, $q, ${$_[0]});
7401             #~ bless \$q, __PACKAGE__;
7402              
7403             ## Version 2
7404             Math::MPFR::Rmpfr_mul_q($fr, $fr, ${$_[0]}, $ROUND);
7405             _mpfr2big($fr);
7406             }
7407              
7408             =head2 rad2deg
7409              
7410             $x->rad2deg # => BigNum
7411              
7412             Returns the value of C converted from radians to degrees.
7413              
7414             Example:
7415              
7416             rad2deg(pi) = 180
7417              
7418             =cut
7419              
7420             sub rad2deg {
7421             Math::MPFR::Rmpfr_const_pi((my $pi = Math::MPFR::Rmpfr_init2($PREC)), $ROUND);
7422             Math::MPFR::Rmpfr_ui_div((my $fr = Math::MPFR::Rmpfr_init2($PREC)), 180, $pi, $ROUND);
7423              
7424             ## Version 1
7425             #~ my $q = Math::GMPq::Rmpq_init();
7426             #~ Math::MPFR::Rmpfr_get_q($q, $fr);
7427             #~ Math::GMPq::Rmpq_mul($q, $q, ${$_[0]});
7428             #~ bless \$q, __PACKAGE__;
7429              
7430             ## Version 2
7431             Math::MPFR::Rmpfr_mul_q($fr, $fr, ${$_[0]}, $ROUND);
7432             _mpfr2big($fr);
7433             }
7434              
7435             =head1 * Dissections
7436              
7437             =cut
7438              
7439             =head2 digits
7440              
7441             $x->digits # => (Scalar, Scalar, ...)
7442             $x->digits(Scalar) # => (Scalar, Scalar, ...)
7443              
7444             Returns a list with the digits of C in a given base. When no base is specified, it defaults to base 10.
7445              
7446             Only the absolute integer part of C is considered.
7447              
7448             Example:
7449              
7450             digits(-1234.56) = (1,2,3,4)
7451             digits(4095, 16) = ('f','f','f')
7452              
7453             =cut
7454              
7455             Class::Multimethods::multimethod digits => qw(Math::BigNum) => sub {
7456             my $z = Math::GMPz::Rmpz_init();
7457             Math::GMPz::Rmpz_set_q($z, ${$_[0]});
7458             Math::GMPz::Rmpz_abs($z, $z);
7459             split(//, Math::GMPz::Rmpz_get_str($z, 10));
7460             };
7461              
7462             Class::Multimethods::multimethod digits => qw(Math::BigNum $) => sub {
7463             my ($x, $y) = @_;
7464              
7465             if ($y < 2 or $y > 36) {
7466             require Carp;
7467             Carp::croak("base must be between 2 and 36, got $y");
7468             }
7469              
7470             my $z = Math::GMPz::Rmpz_init();
7471             Math::GMPz::Rmpz_set_q($z, $$x);
7472             Math::GMPz::Rmpz_abs($z, $z);
7473             split(//, Math::GMPz::Rmpz_get_str($z, $y));
7474             };
7475              
7476             Class::Multimethods::multimethod digits => qw(Math::BigNum Math::BigNum) => sub {
7477             $_[0]->digits(CORE::int(Math::GMPq::Rmpq_get_d(${$_[1]})));
7478             };
7479              
7480             =head2 numerator
7481              
7482             $x->numerator # => BigNum
7483              
7484             Returns a copy of the numerator as signed BigNum.
7485              
7486             =cut
7487              
7488             sub numerator {
7489             my ($x) = @_;
7490             my $z = Math::GMPz::Rmpz_init();
7491             Math::GMPq::Rmpq_numref($z, $$x);
7492             _mpz2big($z);
7493             }
7494              
7495             =head2 denominator
7496              
7497             $x->denominator # => BigNum
7498              
7499             Returns a copy of the denominator as positive BigNum.
7500              
7501             =cut
7502              
7503             sub denominator {
7504             my ($x) = @_;
7505             my $z = Math::GMPz::Rmpz_init();
7506             Math::GMPq::Rmpq_denref($z, $$x);
7507             _mpz2big($z);
7508             }
7509              
7510             =head2 parts
7511              
7512             $x->parts # => (BigNum, BigNum)
7513              
7514             Returns a copy of the numerator (signed) and a copy of the denominator (unsigned) as BigNum objects.
7515              
7516             Example:
7517              
7518             parts(-0.75) = (-3, 4)
7519              
7520             =cut
7521              
7522             sub parts {
7523             my ($x) = @_;
7524             my $num_z = Math::GMPz::Rmpz_init();
7525             my $den_z = Math::GMPz::Rmpz_init();
7526             Math::GMPq::Rmpq_numref($num_z, $$x);
7527             Math::GMPq::Rmpq_denref($den_z, $$x);
7528             (_mpz2big($num_z), _mpz2big($den_z));
7529             }
7530              
7531             =head1 * Comparisons
7532              
7533             =cut
7534              
7535             =head2 eq
7536              
7537             $x->eq(BigNum) # => Bool
7538             $x->eq(Scalar) # => Bool
7539              
7540             $x == $y # => Bool
7541              
7542             Equality check: returns a true value when C and C are equal.
7543              
7544             =cut
7545              
7546             Class::Multimethods::multimethod eq => qw(Math::BigNum Math::BigNum) => sub {
7547             Math::GMPq::Rmpq_equal(${$_[0]}, ${$_[1]});
7548             };
7549              
7550             Class::Multimethods::multimethod eq => qw(Math::BigNum $) => sub {
7551             Math::GMPq::Rmpq_equal(${$_[0]}, _str2mpq($_[1]) // return $_[0]->eq(Math::BigNum->new($_[1])));
7552             };
7553              
7554             =for comment
7555             Class::Multimethods::multimethod eq => qw(Math::BigNum Math::BigNum::Complex) => sub {
7556             my ($x, $y) = @_;
7557             $y->im->is_zero && Math::GMPq::Rmpq_equal($$x, ${$y->re});
7558             };
7559             =cut
7560              
7561             Class::Multimethods::multimethod eq => qw(Math::BigNum *) => sub {
7562             $_[0]->eq(Math::BigNum->new($_[1]));
7563             };
7564              
7565             Class::Multimethods::multimethod eq => qw(Math::BigNum Math::BigNum::Inf) => sub { 0 };
7566             Class::Multimethods::multimethod eq => qw(Math::BigNum Math::BigNum::Nan) => sub { 0 };
7567              
7568             =head2 ne
7569              
7570             $x->ne(BigNum) # => Bool
7571             $x->ne(Scalar) # => Bool
7572              
7573             $x != $y # => Bool
7574              
7575             Inequality check: returns a true value when C and C are not equal.
7576              
7577             =cut
7578              
7579             Class::Multimethods::multimethod ne => qw(Math::BigNum Math::BigNum) => sub {
7580             !Math::GMPq::Rmpq_equal(${$_[0]}, ${$_[1]});
7581             };
7582              
7583             Class::Multimethods::multimethod ne => qw(Math::BigNum $) => sub {
7584             !Math::GMPq::Rmpq_equal(${$_[0]}, _str2mpq($_[1]) // return $_[0]->ne(Math::BigNum->new($_[1])));
7585             };
7586              
7587             =for comment
7588             Class::Multimethods::multimethod ne => qw(Math::BigNum Math::BigNum::Complex) => sub {
7589             my ($x, $y) = @_;
7590             !($y->im->is_zero && Math::GMPq::Rmpq_equal($$x, ${$y->re}));
7591             };
7592             =cut
7593              
7594             Class::Multimethods::multimethod ne => qw(Math::BigNum *) => sub {
7595             $_[0]->ne(Math::BigNum->new($_[1]));
7596             };
7597              
7598             Class::Multimethods::multimethod ne => qw(Math::BigNum Math::BigNum::Inf) => sub { 1 };
7599             Class::Multimethods::multimethod ne => qw(Math::BigNum Math::BigNum::Nan) => sub { 1 };
7600              
7601             =head2 gt
7602              
7603             $x->gt(BigNum) # => Bool
7604             $x->gt(Scalar) # => Bool
7605              
7606             BigNum > BigNum # => Bool
7607             BigNum > Scalar # => Bool
7608             Scalar > BigNum # => Bool
7609              
7610             Returns a true value when C is greater than C.
7611              
7612             =cut
7613              
7614             Class::Multimethods::multimethod gt => qw(Math::BigNum Math::BigNum) => sub {
7615             Math::GMPq::Rmpq_cmp(${$_[0]}, ${$_[1]}) > 0;
7616             };
7617              
7618             Class::Multimethods::multimethod gt => qw(Math::BigNum $) => sub {
7619             $_[0]->cmp($_[1]) > 0;
7620             };
7621              
7622             Class::Multimethods::multimethod gt => qw($ Math::BigNum) => sub {
7623             $_[1]->cmp($_[0]) < 0;
7624             };
7625              
7626             =for comment
7627             Class::Multimethods::multimethod gt => qw(Math::BigNum Math::BigNum::Complex) => sub {
7628             $_[1]->lt($_[0]);
7629             };
7630             =cut
7631              
7632             Class::Multimethods::multimethod gt => qw(* Math::BigNum) => sub {
7633             Math::BigNum->new($_[0])->gt($_[1]);
7634             };
7635              
7636             Class::Multimethods::multimethod gt => qw(Math::BigNum *) => sub {
7637             $_[0]->gt(Math::BigNum->new($_[1]));
7638             };
7639              
7640             Class::Multimethods::multimethod gt => qw(Math::BigNum Math::BigNum::Inf) => sub { $_[1]->is_neg };
7641             Class::Multimethods::multimethod gt => qw(Math::BigNum Math::BigNum::Nan) => sub { 0 };
7642              
7643             =head2 ge
7644              
7645             $x->ge(BigNum) # => Bool
7646             $x->ge(Scalar) # => Bool
7647              
7648             BigNum >= BigNum # => Bool
7649             BigNum >= Scalar # => Bool
7650             Scalar >= BigNum # => Bool
7651              
7652             Returns a true value when C is equal or greater than C.
7653              
7654             =cut
7655              
7656             Class::Multimethods::multimethod ge => qw(Math::BigNum Math::BigNum) => sub {
7657             Math::GMPq::Rmpq_cmp(${$_[0]}, ${$_[1]}) >= 0;
7658             };
7659              
7660             Class::Multimethods::multimethod ge => qw(Math::BigNum $) => sub {
7661             $_[0]->cmp($_[1]) >= 0;
7662             };
7663              
7664             Class::Multimethods::multimethod ge => qw($ Math::BigNum) => sub {
7665             $_[1]->cmp($_[0]) <= 0;
7666             };
7667              
7668             =for comment
7669             Class::Multimethods::multimethod ge => qw(Math::BigNum Math::BigNum::Complex) => sub {
7670             $_[1]->le($_[0]);
7671             };
7672             =cut
7673              
7674             Class::Multimethods::multimethod ge => qw(* Math::BigNum) => sub {
7675             Math::BigNum->new($_[0])->ge($_[1]);
7676             };
7677              
7678             Class::Multimethods::multimethod ge => qw(Math::BigNum *) => sub {
7679             $_[0]->ge(Math::BigNum->new($_[1]));
7680             };
7681              
7682             Class::Multimethods::multimethod ge => qw(Math::BigNum Math::BigNum::Inf) => sub { $_[1]->is_neg };
7683             Class::Multimethods::multimethod ge => qw(Math::BigNum Math::BigNum::Nan) => sub { 0 };
7684              
7685             =head2 lt
7686              
7687             $x->lt(BigNum) # => Bool
7688             $x->lt(Scalar) # => Bool
7689              
7690             BigNum < BigNum # => Bool
7691             BigNum < Scalar # => Bool
7692             Scalar < BigNum # => Bool
7693              
7694             Returns a true value when C is less than C.
7695              
7696             =cut
7697              
7698             Class::Multimethods::multimethod lt => qw(Math::BigNum Math::BigNum) => sub {
7699             Math::GMPq::Rmpq_cmp(${$_[0]}, ${$_[1]}) < 0;
7700             };
7701              
7702             Class::Multimethods::multimethod lt => qw(Math::BigNum $) => sub {
7703             $_[0]->cmp($_[1]) < 0;
7704             };
7705              
7706             Class::Multimethods::multimethod lt => qw($ Math::BigNum) => sub {
7707             $_[1]->cmp($_[0]) > 0;
7708             };
7709              
7710             =for comment
7711             Class::Multimethods::multimethod lt => qw(Math::BigNum Math::BigNum::Complex) => sub {
7712             $_[1]->gt($_[0]);
7713             };
7714             =cut
7715              
7716             Class::Multimethods::multimethod lt => qw(* Math::BigNum) => sub {
7717             Math::BigNum->new($_[0])->lt($_[1]);
7718             };
7719              
7720             Class::Multimethods::multimethod lt => qw(Math::BigNum *) => sub {
7721             $_[0]->lt(Math::BigNum->new($_[1]));
7722             };
7723              
7724             Class::Multimethods::multimethod lt => qw(Math::BigNum Math::BigNum::Inf) => sub { $_[1]->is_pos };
7725             Class::Multimethods::multimethod lt => qw(Math::BigNum Math::BigNum::Nan) => sub { 0 };
7726              
7727             =head2 le
7728              
7729             $x->le(BigNum) # => Bool
7730             $x->le(Scalar) # => Bool
7731              
7732             BigNum <= BigNum # => Bool
7733             BigNum <= Scalar # => Bool
7734             Scalar <= BigNum # => Bool
7735              
7736             Returns a true value when C is equal or less than C.
7737              
7738             =cut
7739              
7740             Class::Multimethods::multimethod le => qw(Math::BigNum Math::BigNum) => sub {
7741             Math::GMPq::Rmpq_cmp(${$_[0]}, ${$_[1]}) <= 0;
7742             };
7743              
7744             Class::Multimethods::multimethod le => qw(Math::BigNum $) => sub {
7745             $_[0]->cmp($_[1]) <= 0;
7746             };
7747              
7748             Class::Multimethods::multimethod le => qw($ Math::BigNum) => sub {
7749             $_[1]->cmp($_[0]) >= 0;
7750             };
7751              
7752             =for comment
7753             Class::Multimethods::multimethod le => qw(Math::BigNum Math::BigNum::Complex) => sub {
7754             $_[1]->ge($_[0]);
7755             };
7756             =cut
7757              
7758             Class::Multimethods::multimethod le => qw(* Math::BigNum) => sub {
7759             Math::BigNum->new($_[0])->le($_[1]);
7760             };
7761              
7762             Class::Multimethods::multimethod le => qw(Math::BigNum *) => sub {
7763             $_[0]->le(Math::BigNum->new($_[1]));
7764             };
7765              
7766             Class::Multimethods::multimethod le => qw(Math::BigNum Math::BigNum::Inf) => sub { $_[1]->is_pos };
7767             Class::Multimethods::multimethod le => qw(Math::BigNum Math::BigNum::Nan) => sub { 0 };
7768              
7769             =head2 cmp
7770              
7771             $x->cmp(BigNum) # => Scalar
7772             $x->cmp(Scalar) # => Scalar
7773              
7774             BigNum <=> BigNum # => Scalar
7775             BigNum <=> Scalar # => Scalar
7776             Scalar <=> BigNum # => Scalar
7777              
7778             Compares C to C and returns a negative value when C is less than C,
7779             0 when C and C are equal, and a positive value when C is greater than C.
7780              
7781             =cut
7782              
7783             Class::Multimethods::multimethod cmp => qw(Math::BigNum Math::BigNum) => sub {
7784             Math::GMPq::Rmpq_cmp(${$_[0]}, ${$_[1]});
7785             };
7786              
7787             Class::Multimethods::multimethod cmp => qw(Math::BigNum $) => sub {
7788             my ($x, $y) = @_;
7789              
7790             if (CORE::int($y) eq $y and $y >= MIN_SI and $y <= MAX_UI) {
7791             $y >= 0
7792             ? Math::GMPq::Rmpq_cmp_ui($$x, $y, 1)
7793             : Math::GMPq::Rmpq_cmp_si($$x, $y, 1);
7794             }
7795             else {
7796             Math::GMPq::Rmpq_cmp($$x, _str2mpq($y) // return $x->cmp(Math::BigNum->new($y)));
7797             }
7798             };
7799              
7800             Class::Multimethods::multimethod cmp => qw($ Math::BigNum) => sub {
7801             my ($x, $y) = @_;
7802              
7803             if (CORE::int($x) eq $x and $x >= MIN_SI and $x <= MAX_UI) {
7804             -(
7805             $x >= 0
7806             ? Math::GMPq::Rmpq_cmp_ui($$y, $x, 1)
7807             : Math::GMPq::Rmpq_cmp_si($$y, $x, 1)
7808             );
7809             }
7810             else {
7811             Math::GMPq::Rmpq_cmp(_str2mpq($x) // (return Math::BigNum->new($x)->cmp($y)), $$y);
7812             }
7813             };
7814              
7815             Class::Multimethods::multimethod cmp => qw(* Math::BigNum) => sub {
7816             Math::BigNum->new($_[0])->cmp($_[1]);
7817             };
7818              
7819             Class::Multimethods::multimethod cmp => qw(Math::BigNum *) => sub {
7820             $_[0]->cmp(Math::BigNum->new($_[1]));
7821             };
7822              
7823             Class::Multimethods::multimethod cmp => qw(Math::BigNum Math::BigNum::Inf) => sub { $_[1]->is_pos ? -1 : 1 };
7824             Class::Multimethods::multimethod cmp => qw(Math::BigNum Math::BigNum::Nan) => sub { };
7825              
7826             =head2 acmp
7827              
7828             $x->acmp(BigNum) # => Scalar
7829             cmp(Scalar, BigNum) # => Scalar
7830              
7831             Compares the absolute values of C and C. Returns a negative value
7832             when the absolute value of C is less than the absolute value of C,
7833             0 when the absolute value of C is equal to the absolute value of C,
7834             and a positive value when the absolute value of C is greater than the
7835             absolute value of C.
7836              
7837             =cut
7838              
7839             Class::Multimethods::multimethod acmp => qw(Math::BigNum Math::BigNum) => sub {
7840             my ($x, $y) = @_;
7841              
7842             my $xn = $$x;
7843             my $yn = $$y;
7844              
7845             if (Math::GMPq::Rmpq_sgn($xn) < 0) {
7846             my $r = Math::GMPq::Rmpq_init();
7847             Math::GMPq::Rmpq_abs($r, $xn);
7848             $xn = $r;
7849             }
7850              
7851             if (Math::GMPq::Rmpq_sgn($yn) < 0) {
7852             my $r = Math::GMPq::Rmpq_init();
7853             Math::GMPq::Rmpq_abs($r, $yn);
7854             $yn = $r;
7855             }
7856              
7857             Math::GMPq::Rmpq_cmp($xn, $yn);
7858             };
7859              
7860             Class::Multimethods::multimethod acmp => qw(Math::BigNum $) => sub {
7861             my ($x, $y) = @_;
7862              
7863             my $xn = $$x;
7864              
7865             if (Math::GMPq::Rmpq_sgn($xn) < 0) {
7866             my $r = Math::GMPq::Rmpq_init();
7867             Math::GMPq::Rmpq_abs($r, $xn);
7868             $xn = $r;
7869             }
7870              
7871             if (CORE::int($y) eq $y and $y >= MIN_SI and $y <= MAX_UI) {
7872             Math::GMPq::Rmpq_cmp_ui($xn, CORE::abs($y), 1);
7873             }
7874             else {
7875             my $q = _str2mpq($y) // return $x->acmp(Math::BigNum->new($y));
7876             Math::GMPq::Rmpq_abs($q, $q);
7877             Math::GMPq::Rmpq_cmp($xn, $q);
7878             }
7879             };
7880              
7881             Class::Multimethods::multimethod acmp => qw(Math::BigNum *) => sub {
7882             $_[0]->acmp(Math::BigNum->new($_[1]));
7883             };
7884              
7885             Class::Multimethods::multimethod acmp => qw(Math::BigNum Math::BigNum::Inf) => sub { -1 };
7886             Class::Multimethods::multimethod acmp => qw(Math::BigNum Math::BigNum::Nan) => sub { };
7887              
7888             =head2 min
7889              
7890             $x->min(BigNum) # => BigNum
7891              
7892             Returns C if C is lower than C. Returns C otherwise.
7893              
7894             =cut
7895              
7896             Class::Multimethods::multimethod min => qw(Math::BigNum Math::BigNum) => sub {
7897             my ($x, $y) = @_;
7898             Math::GMPq::Rmpq_cmp($$x, $$y) < 0 ? $x : $y;
7899             };
7900              
7901             Class::Multimethods::multimethod min => qw(Math::BigNum *) => sub {
7902             $_[0]->min(Math::BigNum->new($_[1]));
7903             };
7904              
7905             Class::Multimethods::multimethod min => qw(Math::BigNum Math::BigNum::Inf) => sub { $_[1]->is_pos ? $_[0] : $_[1] };
7906             Class::Multimethods::multimethod min => qw(Math::BigNum Math::BigNum::Nan) => sub { $_[1] };
7907              
7908             =head2 max
7909              
7910             $x->max(BigNum) # => BigNum
7911              
7912             Returns C if C is greater than C. Returns C otherwise.
7913              
7914             =cut
7915              
7916             Class::Multimethods::multimethod max => qw(Math::BigNum Math::BigNum) => sub {
7917             my ($x, $y) = @_;
7918             Math::GMPq::Rmpq_cmp($$x, $$y) > 0 ? $x : $y;
7919             };
7920              
7921             Class::Multimethods::multimethod max => qw(Math::BigNum *) => sub {
7922             $_[0]->max(Math::BigNum->new($_[1]));
7923             };
7924              
7925             Class::Multimethods::multimethod max => qw(Math::BigNum Math::BigNum::Inf) => sub { $_[1]->is_pos ? $_[1] : $_[0] };
7926             Class::Multimethods::multimethod max => qw(Math::BigNum Math::BigNum::Nan) => sub { $_[1] };
7927              
7928             =head1 AUTHOR
7929              
7930             Daniel Șuteu, C<< >>
7931              
7932             =head1 BUGS
7933              
7934             Please report any bugs or feature requests to C, or through
7935             the web interface at L. I will be notified, and then you'll
7936             automatically be notified of progress on your bug as I make changes.
7937              
7938             =head1 SUPPORT
7939              
7940             You can find documentation for this module with the perldoc command.
7941              
7942             perldoc Math::BigNum
7943              
7944              
7945             You can also look for information at:
7946              
7947             =over 4
7948              
7949             =item * RT: CPAN's request tracker (report bugs here)
7950              
7951             L
7952              
7953             =item * AnnoCPAN: Annotated CPAN documentation
7954              
7955             L
7956              
7957             =item * CPAN Ratings
7958              
7959             L
7960              
7961             =item * Search CPAN
7962              
7963             L
7964              
7965             =item * GitHub
7966              
7967             L
7968              
7969             =back
7970              
7971             =head1 ACKNOWLEDGEMENTS
7972              
7973             =over 4
7974              
7975             =item * Rounding
7976              
7977             L
7978              
7979             =item * Special cases and NaN
7980              
7981             L
7982              
7983             =item * What Every Computer Scientist Should Know About FloatingPoint Arithmetic
7984              
7985             L
7986              
7987             =item * Wolfram|Alpha
7988              
7989             L
7990              
7991             =back
7992              
7993             =head1 SEE ALSO
7994              
7995             =over 4
7996              
7997             =item * Fast math libraries
7998              
7999             L - High speed arbitrary size integer math.
8000              
8001             L - perl interface to the GMP library's integer (mpz) functions.
8002              
8003             L - perl interface to the GMP library's rational (mpq) functions.
8004              
8005             L - perl interface to the MPFR (floating point) library.
8006              
8007             =item * Portable math libraries
8008              
8009             L - Arbitrary size integer/float math package.
8010              
8011             L - Arbitrary size floating point math package.
8012              
8013             L - Arbitrary big rational numbers.
8014              
8015             =item * Math utilities
8016              
8017             L - Utilities related to prime numbers, including fast sieves and factoring.
8018              
8019             =back
8020              
8021             =head1 LICENSE AND COPYRIGHT
8022              
8023             Copyright 2016-2017 Daniel Șuteu.
8024              
8025             This program is free software; you can redistribute it and/or modify it
8026             under the terms of the the Artistic License (2.0). You may obtain a
8027             copy of the full license at:
8028              
8029             L
8030              
8031             Any use, modification, and distribution of the Standard or Modified
8032             Versions is governed by this Artistic License. By using, modifying or
8033             distributing the Package, you accept this license. Do not use, modify,
8034             or distribute the Package, if you do not accept this license.
8035              
8036             If your Modified Version has been derived from a Modified Version made
8037             by someone other than you, you are nevertheless required to ensure that
8038             your Modified Version complies with the requirements of this license.
8039              
8040             This license does not grant you the right to use any trademark, service
8041             mark, tradename, or logo of the Copyright Holder.
8042              
8043             This license includes the non-exclusive, worldwide, free-of-charge
8044             patent license to make, have made, use, offer to sell, sell, import and
8045             otherwise transfer the Package with respect to any patent claims
8046             licensable by the Copyright Holder that are necessarily infringed by the
8047             Package. If you institute patent litigation (including a cross-claim or
8048             counterclaim) against any party alleging that the Package constitutes
8049             direct or contributory patent infringement, then this Artistic License
8050             to you shall terminate on the date that such litigation is filed.
8051              
8052             Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER
8053             AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.
8054             THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
8055             PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY
8056             YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR
8057             CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR
8058             CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE,
8059             EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
8060              
8061              
8062             =cut
8063              
8064             1; # End of Math::BigNum